Archived
feat(w05): 重做的意见交回给 AI 重跑那一步 —— 不再只是把派生列重算一遍
用户:「唯一调用 ai 的这一步,使用重做后是否没有将重做原因带回去重新让 ai 重跑这一步?」 确实没有:S3 那一轮只跑三笔纯投影重算,人写的那句话除了留痕之外无人读 —— AI 判过的四态一个字不会变,除非他自己在件上逐格改。 平台:引擎把「人这次打回写了什么」注给配方(`case_redo_note`)。 · 下划线不是 case: 前缀 —— S-FEEL 的名字不许带冒号,而它最要紧的用法就是当 when 条件用; · **没打回也永远绑着空串**:未绑定的名字 `!= ""` 求值为真,不绑就等于那几笔每一轮都跑 (拿真 @sfeel 钉了这条,桩也照真语义写,否则钉不住); · 静态审认这个名字 —— 它当场拦下过一次未登记的引用,这道门做对了事。 W05@2.17.0:S3 多两笔,都钉在 `case_redo_note != ""` 上 —— 带意见重判(入参多带上一轮四态/影响/依据/UNKNOWN 去向 + 他那句话;判法与第一轮同一份 ASSESS_RULES,后接复核纪律:没被点到、也确实没判错的行原样带回,别趁重判把人改过的冲掉) + 判完落回明细(与第一轮同一笔投影,只多一个 when)。判法、出参形状、落明细抽成三个 共享常量,S2 与 S3 共用 —— 各写一份早晚分叉。 验收:e2e w05 5/5 released、被拒 0;案例 0(先点名驳回、再通过)模型调用恰 2 次, 其余四例仍是 1 次 —— 没被打回就不多花一次模型。auto-runner 3 测(含变异验证)、包内 +1。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -43,6 +43,16 @@ export type AutoContext = {
|
||||
readonly quiet: boolean;
|
||||
/** 这一步已经发过卡(worldTouched) */
|
||||
readonly carded: boolean;
|
||||
/**
|
||||
* **人把这一步打回重做时写下的那句话**(2026-08-31 用户定:「重做后要把原因带回去,
|
||||
* 让 AI 重跑这一步」)—— 没有打回就是空串,**永远绑得上**:S-FEEL 里未绑定的名字参与
|
||||
* 比较会翻车(`!= ""` 求值为真),那正好会让「只在被打回时才跑」的那几笔每一轮都跑。
|
||||
*
|
||||
* 配方里的名字是 **`case_redo_note`**(下划线,不是 `case:` 前缀)—— S-FEEL 的名字只认
|
||||
* `[A-Za-z0-9_一-龥]`(`packages/sfeel/src/lexer.ts` 的 NAME_PART),带冒号的名字
|
||||
* 写不进 `when` 条件;而这句话最要紧的用法恰恰是当条件用。
|
||||
*/
|
||||
readonly redoNote?: string | undefined;
|
||||
};
|
||||
|
||||
export type AutoOutcome = {
|
||||
@@ -98,7 +108,9 @@ export function createAutoRunner(deps: AutoRunnerDeps): {
|
||||
async run(recipe, ctx) {
|
||||
const writable = await deps.data.writable(ctx.taskId);
|
||||
const results: Record<string, unknown[]> = {};
|
||||
let scope: Record<string, unknown> = { ...(await deps.data.view(ctx.taskId)), ...results };
|
||||
/* 人打回时写的那句话:没有就是空串(见 `AutoContext.redoNote` 的头注 —— 必须永远绑得上) */
|
||||
const redoNote = { case_redo_note: ctx.redoNote ?? '' };
|
||||
let scope: Record<string, unknown> = { ...(await deps.data.view(ctx.taskId)), ...redoNote, ...results };
|
||||
let dirty = false;
|
||||
let wrote = 0;
|
||||
let dropped = 0;
|
||||
@@ -391,7 +403,7 @@ export function createAutoRunner(deps: AutoRunnerDeps): {
|
||||
for (const [index, action] of recipe.do.entries()) {
|
||||
try {
|
||||
if (dirty) {
|
||||
scope = { ...(await deps.data.view(ctx.taskId)), ...results };
|
||||
scope = { ...(await deps.data.view(ctx.taskId)), ...redoNote, ...results };
|
||||
dirty = false;
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -2102,6 +2102,8 @@ export function createTurnRunner(deps: TurnRunnerDeps): LoopEngineService {
|
||||
humanCallCap: (await deps.tasks.of(taskId)).humanCallCap,
|
||||
quiet: false,
|
||||
carded: touchedItem && settled,
|
||||
/* 打回那句话交给配方(`case_redo_note`)—— 活动据它决定这一轮要不要把意见交回给 AI 重跑 */
|
||||
...(settled || answer?.chose === undefined ? {} : { redoNote: answer.chose.startsWith('custom:') ? answer.chose.slice(7).trim() : answer.chose }),
|
||||
});
|
||||
if (auto.failedAt !== undefined) {
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user