问题Subagent 继承的是 概述
本次事故中,分叉由 GUI 冷恢复路径引入:它用部署默认模型播种 严重度Critical —— 静默跨 provider 计费 / 成本泄漏,附带错误模型执行。财务影响只有去 provider 账单页才看得到。 环境
真实事故时间线(UTC+8):
观测到的父/子分叉:
成本:树内 61 个子会话,token 字段合计 ≈ input 471 万 / output 190 万 / reasoning 109 万(≈ 770 万),全部记到错误的provider,而父 agent 的流量一直走原路由。 根因1. subagent 继承读的是 options,不是实际路由
function resolveChildAgentOptions(parent, requested, childDepth) {
const parentProvider = parent.options.provider;
const parentModel = parent.options.model;
const parentMaxTokens = parent.options.maxTokens;
return {
...parentProvider !== void 0 ? { provider: parentProvider } : {},
...parentModel !== void 0 ? { model: parentModel } : {},
...parentMaxTokens !== void 0 ? { maxTokens: parentMaxTokens } : {},
...requested,
subagentDepth: childDepth
};
}
2a. 冷恢复用部署默认模型播种 options,同时把路由钉在会话日志上
/** The seed model each create/resume declares; re-read so it never goes stale. */
const agentOptions = () => {
const { provider, model } = defaults.defaultModelSelection();
return { provider, model };
};这个闭包同时用于全新创建和冷恢复(经 而
父 agent 自己的 LLM 调用因此继续走持久化路由(正确),但 2b. GUI 模型选择器在活跃会话上有同样的分叉模型选择 RPC(host-apiproxy 2701 行): selectionFor(found.agent).current = selected;它只写请求级 selection,从不写 最小复现复现 A —— GUI 模型选择器(无需重启):
复现 B —— 冷恢复:
|
Replies: 2 comments
|
这份 RCA 是这一族里最完整的一份(定位到 你的标题在削弱你自己的发现标题写的是「GUI 冷恢复后默认切回 dsv4p」,但你自己的复现 A 是这样的:
以及正文里那句:
这两件事的影响面差着一个数量级。 冷恢复要求宿主先重启过;而 2b 只要求"在 GUI 里换过一次模型"——那是每个用第三方 provider 的人每天都在做的动作。也就是说:不是"重启过的会话有风险",是**"任何换过模型的会话,从那一刻起派生的每个子代理都记在默认 provider 账上"**。 为什么这值得单独说:维护者按标题分诊时,很容易把修复范围圈在 resume 路径上( 建议把标题改成后果 + 触发条件的宽口径,比如「subagent 继承 关于 @Cfomodz 说的重复他指的 #1581 / #1472 / #2006 / #2053 确实同源。但重复不等于冗余——这一族现在有五份独立报告,各自贡献的证据类型不同,而你这份是唯一同时具备"根因定位到函数 + 两条分叉路径分别可复现 + 实际计费金额"的。 对维护者来说更有用的做法可能是:在你这帖里把五份并成一张表(谁贡献了什么证据),然后建议其余四帖指向这里,而不是让五个线程各自半死不活。这一族的说服力在于五个人在五种配置下撞到同一行代码——但只有并起来才看得出来。 一个结构性的观察
这个形状最近在这个社区出现得很密:#2915 是 replay metadata 与持久内容从同一份数据的两个不同版本各自派生、于是长度对不上;#3226 / #3566 是模型声明在归一化时被剥掉一半。共同点是"同一个事实存了两份,只有一份跟着变",而不一致的代价一律由用户承担。 按这个视角,最小修法( 边界与利益相关我们不修 DSH 自家组件—— 利益相关必须披露:我维护 pi2dsh,它能跑一套 Pi 生态的子代理,而那套子代理是按会话当前的实时路由解析模型的,不吃创建期快照(我们有端到端的 example,断言是"父会话 但我不建议你为这个换掉 DSH 原生子代理,理由有三条:① 你要的是这个 bug 被修,换运行时不会让 #1581/#1472/#2006/#2053 那四份报告消失;② 你已经把根因精确到函数和行号了,一行改动的事,不值得换一整套运行时;③ 换过去你会失去 DSH 原生子代理的那些集成。我写这段只是为了把利益相关摊开,不是推销。 |
Duplicate RCA as #1581/#1472/#2006/#2053
Also document correction: JSDoc at runtime-types.ts:67-68