fix: 全量替换 claude-fable-5 → claude-opus-4-8(模型不可用)
- models.ts: 所有档位默认值、回退链、conflict 固定值全部换为 opus-4-8 - 回退链从三项缩为两项 [opus-4-8, sonnet-4-6](删除重复项) - metrics.ts: 额度权重 opus-4-8 升为 1.0(现为最高档) - 测试同步更新 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,10 +36,10 @@ test('metrics 纯函数:percentile / ratio / estimateCostUnits', () => {
|
||||
assert.equal(ratio(2, 3), 0.6667);
|
||||
assert.equal(ratio(0, 0), null); // 无样本不除零
|
||||
|
||||
assert.equal(costPerMin('claude-fable-5'), 1.0);
|
||||
assert.equal(costPerMin('claude-opus-4-8'), 1.0);
|
||||
assert.equal(costPerMin('未知模型'), DEFAULT_COST_PER_MIN);
|
||||
assert.equal(estimateCostUnits(60_000, 'claude-fable-5'), 1.0); // 1 分钟 × 1.0
|
||||
assert.equal(estimateCostUnits(120_000, 'claude-opus-4-8'), 1.2); // 2 分钟 × 0.6
|
||||
assert.equal(estimateCostUnits(60_000, 'claude-opus-4-8'), 1.0); // 1 分钟 × 1.0
|
||||
assert.equal(estimateCostUnits(120_000, 'claude-sonnet-4-6'), 0.4); // 2 分钟 × 0.2
|
||||
});
|
||||
|
||||
// ──────────────── 空数据不崩 ────────────────
|
||||
@@ -166,7 +166,7 @@ test('metrics 按模型额度:时长×档位 粗估,estimated=true', () => {
|
||||
const m = s.metrics(p.id);
|
||||
assert.equal(m.byModel.length, 1);
|
||||
assert.deepEqual(m.byModel[0], {
|
||||
model: 'claude-opus-4-8', runs: 2, durationMs: 120_000, estCostUnits: 1.2, estimated: true,
|
||||
model: 'claude-opus-4-8', runs: 2, durationMs: 120_000, estCostUnits: 2.0, estimated: true,
|
||||
});
|
||||
assert.equal(m.estimated, true);
|
||||
s.close();
|
||||
|
||||
+18
-19
@@ -39,11 +39,11 @@ test('pickModel:复杂度映射默认值(executor / reviewer)', () => {
|
||||
const p = fakeProject();
|
||||
assert.equal(pickModel(fakeTask('easy'), p, 'executor'), 'claude-sonnet-4-6');
|
||||
assert.equal(pickModel(fakeTask('medium'), p, 'executor'), 'claude-opus-4-8');
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'executor'), 'claude-fable-5');
|
||||
// reviewer 三档全升 fable-5(保复审独立性)
|
||||
assert.equal(pickModel(fakeTask('easy'), p, 'reviewer'), 'claude-fable-5');
|
||||
assert.equal(pickModel(fakeTask('medium'), p, 'reviewer'), 'claude-fable-5');
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'reviewer'), 'claude-fable-5');
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'executor'), 'claude-opus-4-8');
|
||||
// reviewer 三档统一 opus-4-8(保复审独立性)
|
||||
assert.equal(pickModel(fakeTask('easy'), p, 'reviewer'), 'claude-opus-4-8');
|
||||
assert.equal(pickModel(fakeTask('medium'), p, 'reviewer'), 'claude-opus-4-8');
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'reviewer'), 'claude-opus-4-8');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,10 +53,10 @@ test('pickModel:project.model executor 最优先,但 reviewer/conflict 不
|
||||
for (const c of ['easy', 'medium', 'hard'] as const) {
|
||||
// executor 受 project.model 覆盖
|
||||
assert.equal(pickModel(fakeTask(c), p, 'executor'), 'claude-opus-4-6');
|
||||
// reviewer 不受 project.model 覆盖,始终用最强档 fable-5(保自审独立性)
|
||||
assert.equal(pickModel(fakeTask(c), p, 'reviewer'), 'claude-fable-5');
|
||||
// conflict 固定 fable-5
|
||||
assert.equal(pickModel(fakeTask(c), p, 'conflict'), 'claude-fable-5');
|
||||
// reviewer 不受 project.model 覆盖,始终用 opus-4-8(保自审独立性)
|
||||
assert.equal(pickModel(fakeTask(c), p, 'reviewer'), 'claude-opus-4-8');
|
||||
// conflict 固定 opus-4-8
|
||||
assert.equal(pickModel(fakeTask(c), p, 'conflict'), 'claude-opus-4-8');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -64,15 +64,15 @@ test('pickModel:project.model executor 最优先,但 reviewer/conflict 不
|
||||
test('pickModel:env 覆盖默认值,executor/reviewer 各用各的 env', () => {
|
||||
withEnv({
|
||||
MAESTRO_MODEL_EASY: 'claude-haiku-4-5',
|
||||
MAESTRO_MODEL_REVIEW_EASY: 'claude-opus-4-8', // reviewer env 可单独覆盖
|
||||
MAESTRO_MODEL_REVIEW_EASY: 'claude-sonnet-4-6', // reviewer env 可单独覆盖
|
||||
}, () => {
|
||||
const p = fakeProject();
|
||||
assert.equal(pickModel(fakeTask('easy'), p, 'executor'), 'claude-haiku-4-5');
|
||||
// reviewer easy 被 MAESTRO_MODEL_REVIEW_EASY 覆盖
|
||||
assert.equal(pickModel(fakeTask('easy'), p, 'reviewer'), 'claude-opus-4-8');
|
||||
// reviewer hard 无 env → 默认 fable-5
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'reviewer'), 'claude-fable-5');
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'executor'), 'claude-fable-5'); // executor hard 默认 fable
|
||||
assert.equal(pickModel(fakeTask('easy'), p, 'reviewer'), 'claude-sonnet-4-6');
|
||||
// reviewer hard 无 env → 默认 opus-4-8
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'reviewer'), 'claude-opus-4-8');
|
||||
assert.equal(pickModel(fakeTask('hard'), p, 'executor'), 'claude-opus-4-8');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -97,10 +97,9 @@ test('isModelError:模型不可用类错误才触发回退', () => {
|
||||
assert.ok(!isModelError('model produced empty output')); // 提到 model 但不是可用性错误
|
||||
});
|
||||
|
||||
test('pickFallbackModel:回退链取第一个 ≠ 失败模型的', () => {
|
||||
// 链已扩展为三项:fable → opus → sonnet
|
||||
assert.deepEqual([...MODEL_FALLBACK_CHAIN], ['claude-fable-5', 'claude-opus-4-8', 'claude-sonnet-4-6']);
|
||||
assert.equal(pickFallbackModel('claude-fable-5'), 'claude-opus-4-8');
|
||||
test('pickFallbackModel:回退链取下一档(循环)', () => {
|
||||
// 链:opus → sonnet → opus(循环)
|
||||
assert.deepEqual([...MODEL_FALLBACK_CHAIN], ['claude-opus-4-8', 'claude-sonnet-4-6']);
|
||||
assert.equal(pickFallbackModel('claude-opus-4-8'), 'claude-sonnet-4-6');
|
||||
assert.equal(pickFallbackModel('claude-sonnet-4-6'), 'claude-fable-5');
|
||||
assert.equal(pickFallbackModel('claude-sonnet-4-6'), 'claude-opus-4-8');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user