一、subagents 工具
1.1 工具概述
功能 :管理已生成的子 agent
核心特性:
- 3 个 actions(list/kill/steer)
- 支持按标签/序号/会话键定位
- 支持批量终止(target=all)
- 消息长度限制(4000 字符)
- 最近活跃度过滤(recentMinutes)
1.2 Schema 定义
位置:第 112950 行
javascript
const SubagentsToolSchema = Type.Object({
action: optionalStringEnum$3(["list", "kill", "steer"]),
target: Type.Optional(Type.String()),
message: Type.Optional(Type.String()),
recentMinutes: Type.Optional(Type.Number({ minimum: 1 }))
});
1.3 完整执行代码
位置:第 112961 行
javascript
function createSubagentsTool(opts) {
return {
label: "Subagents",
name: "subagents",
description: "List, kill, or steer spawned sub-agents for this requester session. Use this for sub-agent orchestration.",
parameters: SubagentsToolSchema,
execute: async (_toolCallId, args) => {
const params = args;
// 1. 解析 action(默认 list)
const action = readStringParam$1(params, "action") ?? "list";
const cfg = loadConfig();
// 2. 解析子 agent 控制器
const controller = resolveSubagentController({
cfg,
agentSessionKey: opts?.agentSessionKey
});
// 3. 获取子 agent 运行列表
const runs = listControlledSubagentRuns(controller.controllerSessionKey);
const recentMinutesRaw = readNumberParam(params, "recentMinutes");
const recentMinutes = recentMinutesRaw ?
Math.max(1, Math.min(MAX_RECENT_MINUTES, Math.floor(recentMinutesRaw))) : 30;
const pendingDescendantCount = createPendingDescendantCounter();
const isActive = (entry) => isActiveSubagentRun(entry, pendingDescendantCount);
// === action: list ===
if (action === "list") {
const list = buildSubagentList({
cfg,
runs,
recentMinutes
});
return jsonResult({
status: "ok",
action: "list",
requesterSessionKey: controller.controllerSessionKey,
callerSessionKey: controller.callerSessionKey,
callerIsSubagent: controller.callerIsSubagent,
total: list.total,
active: list.active.map(({ line: _line, ...view }) => view),
recent: list.recent.map(({ line: _line, ...view }) => view),
text: list.text
});
}
// === action: kill ===
if (action === "kill") {
const target = readStringParam$1(params, "target", { required: true });
// 批量终止
if (target === "all" || target === "*") {
const result = await killAllControlledSubagentRuns({
cfg,
controller,
runs
});
if (result.status === "forbidden") {
return jsonResult({
status: "forbidden",
action: "kill",
target: "all",
error: result.error
});
}
return jsonResult({
status: "ok",
action: "kill",
target: "all",
killed: result.killed,
labels: result.labels,
text: result.killed > 0 ?
`killed ${result.killed} subagent${result.killed === 1 ? "" : "s"}.` :
"no running subagents to kill."
});
}
// 单个终止
const resolved = resolveControlledSubagentTarget(runs, target, {
recentMinutes,
isActive
});
if (!resolved.entry) {
return jsonResult({
status: "error",
action: "kill",
target,
error: resolved.error ?? "Unknown subagent target."
});
}
const result = await killControlledSubagentRun({
cfg,
controller,
entry: resolved.entry
});
return jsonResult({
status: result.status,
action: "kill",
target,
runId: result.runId,
sessionKey: result.sessionKey,
label: result.label,
cascadeKilled: "cascadeKilled" in result ? result.cascadeKilled : void 0,
cascadeLabels: "cascadeLabels" in result ? result.cascadeLabels : void 0,
error: "error" in result ? result.error : void 0,
text: result.text
});
}
// === action: steer ===
if (action === "steer") {
const target = readStringParam$1(params, "target", { required: true });
const message = readStringParam$1(params, "message", { required: true });
// 检查消息长度
if (message.length > 4000) {
return jsonResult({
status: "error",
action: "steer",
target,
error: `Message too long (${message.length} chars, max ${MAX_STEER_MESSAGE_CHARS}).`
});
}
const resolved = resolveControlledSubagentTarget(runs, target, {
recentMinutes,
isActive
});
if (!resolved.entry) {
return jsonResult({
status: "error",
action: "steer",
target,
error: resolved.error ?? "Unknown subagent target."
});
}
const result = await steerControlledSubagentRun({
cfg,
controller,
entry: resolved.entry,
message
});
return jsonResult({
status: result.status,
action: "steer",
target,
runId: result.runId,
sessionKey: result.sessionKey,
sessionId: result.sessionId,
mode: "mode" in result ? result.mode : void 0,
label: "label" in result ? result.label : void 0,
error: "error" in result ? result.error : void 0,
text: result.text
});
}
return jsonResult({
status: "error",
error: "Unsupported action."
});
}
};
}
1.4 子 agent 定位逻辑
javascript
function resolveControlledSubagentTarget(runs, target, options) {
const { recentMinutes, isActive } = options;
// 1. 排序运行列表(按开始时间倒序)
const sorted = sortSubagentRuns(runs);
// 2. 去重(按 childSessionKey)
const deduped = [];
const seenChildSessionKeys = new Set();
for (const entry of sorted) {
if (seenChildSessionKeys.has(entry.childSessionKey)) continue;
seenChildSessionKeys.add(entry.childSessionKey);
deduped.push(entry);
}
// 3. 特殊值:last
if (target === "last") {
return { entry: deduped[0] };
}
// 4. 序号定位(1-based)
if (/^\d+$/.test(target)) {
const idx = Number.parseInt(target, 10);
const numericOrder = [
...deduped.filter((entry) => isActive(entry)),
...deduped.filter((entry) => !isActive(entry) && !!entry.endedAt && (entry.endedAt ?? 0) >= recentCutoff)
];
if (!Number.isFinite(idx) || idx <= 0 || idx > numericOrder.length) {
return { error: `Invalid index: ${target}` };
}
return { entry: numericOrder[idx - 1] };
}
// 5. 会话键定位
if (target.includes(":")) {
const bySessionKey = deduped.find((entry) => entry.childSessionKey === target);
return bySessionKey ? { entry: bySessionKey } : { error: `Unknown session: ${target}` };
}
// 6. 精确标签匹配
const lowered = target.toLowerCase();
const byExactLabel = deduped.filter((entry) => entry.label.toLowerCase() === lowered);
if (byExactLabel.length === 1) {
return { entry: byExactLabel[0] };
}
if (byExactLabel.length > 1) {
return { error: `Ambiguous label: ${target}` };
}
// 7. 标签前缀匹配
const byLabelPrefix = deduped.filter((entry) => entry.label.toLowerCase().startsWith(lowered));
if (byLabelPrefix.length === 1) {
return { entry: byLabelPrefix[0] };
}
if (byLabelPrefix.length > 1) {
return { error: `Ambiguous label prefix: ${target}` };
}
// 8. runId 前缀匹配
const byRunIdPrefix = deduped.filter((entry) => entry.runId.startsWith(target));
if (byRunIdPrefix.length === 1) {
return { entry: byRunIdPrefix[0] };
}
if (byRunIdPrefix.length > 1) {
return { error: `Ambiguous runId prefix: ${target}` };
}
return { error: `Unknown target: ${target}` };
}
1.5 执行流程图
subagents 工具调用
↓
1. 解析 action(list/kill/steer)
↓
2. 解析子 agent 控制器
↓
3. 获取子 agent 运行列表
↓
4. 根据 action 执行
├─ list → 构建列表(活跃 + 最近)
├─ kill → 终止子 agent
│ ├─ target=all → 批量终止
│ └─ target=xxx → 定位后终止
└─ steer → 发送消息给子 agent
├─ 检查消息长度(≤4000)
├─ 定位子 agent
└─ 发送消息
↓
5. 返回结果
1.6 返回结果格式
list 成功:
json
{
"status": "ok",
"action": "list",
"total": 5,
"active": [
{
"runId": "abc123",
"label": "文件分析",
"status": "running",
"startedAt": 1711716000000,
"runtimeMs": 60000
}
],
"recent": [...],
"text": "Active:\n[1] 文件分析 (running, 1m)\n..."
}
kill 成功:
json
{
"status": "ok",
"action": "kill",
"target": "1",
"killed": 1,
"labels": ["文件分析"],
"text": "killed 1 subagent."
}
steer 成功:
json
{
"status": "ok",
"action": "steer",
"target": "文件分析",
"runId": "abc123",
"sessionKey": "subagent:abc123",
"text": "Message sent to subagent."
}
二、gateway 工具
2.1 工具概述
功能 :管理 Gateway 服务
核心特性:
- 仅所有者可用(ownerOnly=true)
- 6 个 actions(restart/config.get/config.schema.lookup/config.apply/config.patch/update.run)
- 配置写入需要 baseHash(乐观锁)
- 重启后通知用户(note 参数)
- SIGUSR1 信号重启
2.2 Schema 定义
位置:第 25780 行
javascript
const GatewayToolSchema = Type.Object({
action: stringEnum([
"restart",
"config.get",
"config.schema.lookup",
"config.apply",
"config.patch",
"update.run"
]),
delayMs: Type.Optional(Type.Number()),
reason: Type.Optional(Type.String()),
gatewayUrl: Type.Optional(Type.String()),
gatewayToken: Type.Optional(Type.String()),
timeoutMs: Type.Optional(Type.Number()),
path: Type.Optional(Type.String()),
raw: Type.Optional(Type.String()),
baseHash: Type.Optional(Type.String()),
sessionKey: Type.Optional(Type.String()),
note: Type.Optional(Type.String()),
restartDelayMs: Type.Optional(Type.Number())
});
2.3 完整执行代码
位置:第 25801 行
javascript
function createGatewayTool(opts) {
return {
label: "Gateway",
name: "gateway",
ownerOnly: true,
description: "Restart, inspect a specific config schema path, apply config, or update the gateway in-place (SIGUSR1). Use config.schema.lookup with a targeted dot path before config edits. Use config.patch for safe partial config updates (merges with existing). Use config.apply only when replacing entire config. Both trigger restart after writing. Always pass a human-readable completion message via the `note` parameter so the system can deliver it to the user after restart.",
parameters: GatewayToolSchema,
execute: async (_toolCallId, args) => {
const params = args;
// 1. 解析 action(必填)
const action = readStringParam$1(params, "action", { required: true });
// === action: restart ===
if (action === "restart") {
// 检查重启是否启用
if (!isRestartEnabled(opts?.config)) {
throw new Error("Gateway restart is disabled (commands.restart=false).");
}
const sessionKey = typeof params.sessionKey === "string" && params.sessionKey.trim() ?
params.sessionKey.trim() : opts?.agentSessionKey?.trim() || void 0;
const delayMs = typeof params.delayMs === "number" && Number.isFinite(params.delayMs) ?
Math.floor(params.delayMs) : void 0;
const reason = typeof params.reason === "string" && params.reason.trim() ?
params.reason.trim().slice(0, 200) : void 0;
const note = typeof params.note === "string" && params.note.trim() ?
params.note.trim() : void 0;
const { deliveryContext, threadId } = extractDeliveryInfo(sessionKey);
// 写入重启 sentinel
const payload = {
kind: "restart",
status: "ok",
ts: Date.now(),
sessionKey,
deliveryContext,
threadId,
message: note ?? reason ?? null,
doctorHint: formatDoctorNonInteractiveHint(),
stats: {
mode: "gateway.restart",
reason
}
};
try {
await writeRestartSentinel(payload);
} catch {}
log$28.info(`gateway tool: restart requested (delayMs=${delayMs ?? "default"}, reason=${reason ?? "none"})`);
return jsonResult(scheduleGatewaySigusr1Restart({
delayMs,
reason
}));
}
// 读取 Gateway 调用选项
const gatewayOpts = readGatewayCallOptions(params);
// 解析 Gateway 写入元数据
const resolveGatewayWriteMeta = () => {
return {
sessionKey: typeof params.sessionKey === "string" && params.sessionKey.trim() ?
params.sessionKey.trim() : opts?.agentSessionKey?.trim() || void 0,
note: typeof params.note === "string" && params.note.trim() ?
params.note.trim() : void 0,
restartDelayMs: typeof params.restartDelayMs === "number" && Number.isFinite(params.restartDelayMs) ?
Math.floor(params.restartDelayMs) : void 0
};
};
// 解析配置写入参数
const resolveConfigWriteParams = async () => {
const raw = readStringParam$1(params, "raw", { required: true });
let baseHash = readStringParam$1(params, "baseHash");
if (!baseHash) {
baseHash = resolveBaseHashFromSnapshot(
await callGatewayTool("config.get", gatewayOpts, {})
);
}
if (!baseHash) {
throw new Error("Missing baseHash from config snapshot.");
}
return {
raw,
baseHash,
...resolveGatewayWriteMeta()
};
};
// === action: config.get ===
if (action === "config.get") {
return jsonResult({
ok: true,
result: await callGatewayTool("config.get", gatewayOpts, {})
});
}
// === action: config.schema.lookup ===
if (action === "config.schema.lookup") {
return jsonResult({
ok: true,
result: await callGatewayTool("config.schema.lookup", gatewayOpts, {
path: readStringParam$1(params, "path", {
required: true,
label: "path"
})
})
});
}
// === action: config.apply ===
if (action === "config.apply") {
const { raw, baseHash, sessionKey, note, restartDelayMs } = await resolveConfigWriteParams();
return jsonResult({
ok: true,
result: await callGatewayTool("config.apply", gatewayOpts, {
raw,
baseHash,
sessionKey,
note,
restartDelayMs
})
});
}
// === action: config.patch ===
if (action === "config.patch") {
const { raw, baseHash, sessionKey, note, restartDelayMs } = await resolveConfigWriteParams();
return jsonResult({
ok: true,
result: await callGatewayTool("config.patch", gatewayOpts, {
raw,
baseHash,
sessionKey,
note,
restartDelayMs
})
});
}
// === action: update.run ===
if (action === "update.run") {
const { sessionKey, note, restartDelayMs } = resolveGatewayWriteMeta();
const updateTimeoutMs = gatewayOpts.timeoutMs ?? DEFAULT_UPDATE_TIMEOUT_MS;
return jsonResult({
ok: true,
result: await callGatewayTool("update.run", {
...gatewayOpts,
timeoutMs: updateTimeoutMs
}, {
sessionKey,
note,
restartDelayMs,
timeoutMs: updateTimeoutMs
})
});
}
throw new Error(`Unknown action: ${action}`);
}
};
}
2.5 配置写入流程
javascript
// 1. 获取当前配置快照
const config = await callGatewayTool("config.get", gatewayOpts, {});
// 2. 提取 baseHash(乐观锁)
const baseHash = resolveBaseHashFromSnapshot(config);
// 3. 准备新配置
const raw = JSON.stringify({ ...config, newSetting: "value" });
// 4. 写入配置(config.apply 或 config.patch)
await callGatewayTool("config.apply", gatewayOpts, {
raw,
baseHash,
sessionKey,
note,
restartDelayMs
});
// 5. Gateway 自动重启(SIGUSR1)
2.6 执行流程图
gateway 工具调用
↓
1. 解析 action(必填)
↓
2. 根据 action 执行
├─ restart → 写入 sentinel + SIGUSR1
├─ config.get → 获取配置
├─ config.schema.lookup → 查询 schema
├─ config.apply → 应用完整配置
├─ config.patch → 应用部分配置
└─ update.run → 执行更新
↓
3. 返回结果
2.7 返回结果格式
restart 成功:
json
{
"ok": true,
"result": {
"status": "scheduled",
"delayMs": 1000,
"reason": "config update"
}
}
config.get 成功:
json
{
"ok": true,
"result": {
"hash": "abc123",
"config": { ... }
}
}
config.apply 失败(baseHash 不匹配):
json
{
"ok": false,
"error": "Config hash mismatch. Please refresh and retry."
}
三、关键机制对比
3.1 权限控制
| 特性 | subagents | gateway |
|---|---|---|
| 所有者限制 | 无 | ownerOnly=true |
| A2A 策略 | 不需要 | 不需要 |
| 可见性检查 | 不需要 | 不需要 |
3.2 操作类型
| 特性 | subagents | gateway |
|---|---|---|
| actions | list/kill/steer | restart/config.* /update.run |
| 定位目标 | target 参数 | 不需要 |
| 批量操作 | target=all | 不支持 |
3.3 安全限制
| 限制类型 | subagents | gateway |
|---|---|---|
| 消息长度 | 4000 字符 | 不支持 |
| 乐观锁 | 不需要 | baseHash 必需 |
| 重启限制 | 不需要 | commands.restart |
四、使用示例
4.1 subagents 工具调用
用户 :列出所有子 agent
大模型返回:
json
{
"tool_call": {
"name": "subagents",
"arguments": { "action": "list" }
}
}
执行结果:
json
{
"status": "ok",
"action": "list",
"total": 3,
"active": [...],
"recent": [...],
"text": "Active:\n[1] 文件分析 (running, 1m)\n[2] 数据处理 (running, 5m)\n..."
}
4.2 gateway 工具调用
用户 :重启 Gateway
大模型返回:
json
{
"tool_call": {
"name": "gateway",
"arguments": {
"action": "restart",
"note": "配置更新完成"
}
}
}
执行结果:
json
{
"ok": true,
"result": {
"status": "scheduled",
"delayMs": 1000,
"reason": null
}
}