Archived
feat(loop-engine): analyze 动词 —— 系统组装入参、声明出参 schema、系统把结果落表
AI 在这里只是一个纯函数:不给工具、不给记忆、不多轮。 行数不由它决定 —— 出参是拿主键去 lookup 的一张查表,它漏一条那一格就是空, required 立刻把它变成 _missing > 0,提交闸与放行门当场拦住。 出参不成形就地重问一次,再不成抛出去交人。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -135,6 +135,36 @@ export function createAutoRunner(deps: AutoRunnerDeps): {
|
||||
return { wrote: localWrote, dropped: localDropped };
|
||||
}
|
||||
|
||||
if (action.kind === 'analyze') {
|
||||
const payload = expandSource(action.input.from, base).map(({ row, outer }) => {
|
||||
const item: Record<string, unknown> = {};
|
||||
for (const [name, expr] of Object.entries(action.input.fields)) {
|
||||
item[name] = evalExpr(expr, { ...base, row, ...(outer === undefined ? {} : { outer }), computed: item });
|
||||
}
|
||||
return item;
|
||||
});
|
||||
const { object } = await deps.analyze.run({
|
||||
taskId: context.taskId,
|
||||
model: action.model,
|
||||
instruction: action.instruction,
|
||||
payload,
|
||||
outputSchema: action.output,
|
||||
label: `${context.stepId}#${index + 1}`,
|
||||
});
|
||||
/* `into` 既是出参里那个数组字段的名字,也是拍内作用域的键 —— 一处声明,两处认 */
|
||||
const rows = object[action.into];
|
||||
results[`result:${action.into}`] = Array.isArray(rows) ? rows : [];
|
||||
await deps.memory.append({
|
||||
taskId: context.taskId,
|
||||
kind: 'result',
|
||||
title: `已把 ${payload.length} 条参数交给模型逐条判定,拿回 ${results[`result:${action.into}`]?.length ?? 0} 条结论`,
|
||||
detail: { auto: `${context.stepId}#${index + 1}`, internal: true, model: action.model },
|
||||
});
|
||||
/* 出参只活在拍内作用域里,不进草稿层 —— 下一笔要能看见它,所以这里也算「脏」 */
|
||||
scope = { ...scope, ...results };
|
||||
return { wrote: 0, dropped: 0 };
|
||||
}
|
||||
|
||||
throw new AutoRecipeError(index, `动词尚未实现:${action.kind}`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user