feat(models+gate): 模型按项目可配置(默认 opus-4.8) + diff 声明外文件硬闸
① 模型可配置(项目维度,默认 opus-4.8)
- 新增 projects.models(JSON,按角色 executor/planner/reviewer/conflict
覆盖,值可为字符串=全复杂度统一 或 {easy,medium,hard} 分档)
- models.ts 重构 resolveModel:优先级 项目级 models > 旧 project.model
(仅 executor/planner) > env > 默认 DEFAULT_MODEL(opus-4.8)
- 取消内置 fable/sonnet 分档默认:所有角色默认 opus-4.8(彻底回避 fable-5
不可用问题,需要时项目级显式配置即可);回退链改 opus→sonnet→fable
- API PATCH /projects 透传 models;sanitizeModels 落库校验
② diff 声明外文件闸(task.scopeFiles)
- 新增 tasks.scope_files(JSON glob/路径数组)
- checks.ts: globToRegExp/matchesAnyGlob + scopeFileGate(改动文件越界=硬闸,
空声明跳过,git 出错不拦截);pipeline runApproveGates 接入
- planner 拆解新增每子任务 files 字段:prompt 要求 + parseDecompose 解析 +
ingest 落 scopeFiles,自动填充声明范围
- executor prompt 注入「声明文件范围约束」,让 agent 知边界(gate 才公平)
迁移:projects.models / tasks.scope_files 走 ensureColumn 幂等迁移(旧库补列)
测试:models 默认/配置/优先级、scope glob/gate、planner files 解析、
store 持久化往返、迁移补列 —— 237 通过
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -101,6 +101,7 @@ export function buildServer(opts: ApiOptions): FastifyInstance {
|
||||
if (b.autoApproveExec !== undefined) patch.autoApproveExec = Boolean(b.autoApproveExec);
|
||||
if (b.checks !== undefined) patch.checks = b.checks === null || b.checks === '' ? null : String(b.checks);
|
||||
if (b.agentRules !== undefined) patch.agentRules = b.agentRules === null || b.agentRules === '' ? null : String(b.agentRules);
|
||||
if (b.models !== undefined) patch.models = b.models === null || b.models === '' ? null : (b.models as PatchProjectInput['models']);
|
||||
return projectOut(store.patchProject(id, patch));
|
||||
});
|
||||
|
||||
@@ -216,6 +217,7 @@ export function buildServer(opts: ApiOptions): FastifyInstance {
|
||||
parentId: b.parentId ? String(b.parentId) : null,
|
||||
priority: b.priority === undefined ? undefined : Number(b.priority),
|
||||
deps: Array.isArray(b.deps) ? (b.deps as string[]) : undefined,
|
||||
scopeFiles: Array.isArray(b.scopeFiles) ? (b.scopeFiles as string[]) : undefined,
|
||||
});
|
||||
if (auto) {
|
||||
// 异步分类回填:classifyComplexity 自身永不抛错(失败兜底 medium),外层再兜一层防御
|
||||
@@ -293,6 +295,12 @@ export function buildServer(opts: ApiOptions): FastifyInstance {
|
||||
}
|
||||
patch.deps = b.deps as string[];
|
||||
}
|
||||
if (b.scopeFiles !== undefined) {
|
||||
if (b.scopeFiles !== null && (!Array.isArray(b.scopeFiles) || !b.scopeFiles.every((f) => typeof f === 'string'))) {
|
||||
throw new StoreError('scopeFiles 必须是文件 glob 字符串数组或 null');
|
||||
}
|
||||
patch.scopeFiles = b.scopeFiles as string[] | null;
|
||||
}
|
||||
return store.patchTask(id, patch);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user