修复(AGC模型): 会员到账后主动刷新模型目录

- confirmNativeRechargePayment 确认订单为 paid 且 kind=membership 时调用 notifyLlmConfigChanged
- 保留 applyCatalog 的 revision 门控不变,由配置变更事件重置已应用 revision 并重新读取
- 补「revision 不变但账号档位变化时,显式通知必须重新应用」的回归测试
This commit is contained in:
2026-10-05 20:22:43 +08:00
parent e27ce5573f
commit d917d2f4d1
2 changed files with 30 additions and 0 deletions
@@ -19,6 +19,7 @@ import {
getClientProfileWalletLedger,
redeemClientProfileRewardCode,
} from '../../services/accountHost';
import { notifyLlmConfigChanged } from '../../services/llmModelCatalog';
import { useWalletStore } from '../../stores/useWalletStore';
export function useAccountWallet(currentUserId: string) {
@@ -363,6 +364,11 @@ export function useAccountWallet(currentUserId: string) {
applyRechargeContent(walletSnapshot, response.center);
if (response.order.status === 'paid') {
setNativeRechargePayment(null);
// 会员到账会改变账号可用的模型档位,但目录 revision 不变;显式通知
// ConversationModelSelect 重置已应用 revision 并重新读取,否则锁定列表保持陈旧。
if (response.order.kind === 'membership') {
notifyLlmConfigChanged();
}
void onWalletBalanceMayHaveChanged();
return;
}
@@ -747,3 +747,27 @@ test('keeps the applied catalog when the revision is unchanged', async () => {
expect(screen.queryByRole('option', { name: '视觉' })).toBeNull();
expect(screen.getByRole('option', { name: '快速' })).not.toBeNull();
});
test('applies a changed account catalog after an explicit config-changed notification', async () => {
const onReady = vi.fn();
render(<ConversationModelSelect disabled={false} onReady={onReady} />);
await waitFor(() => expect(onReady).toHaveBeenLastCalledWith(true));
// 会员升降级只改变账号可用档位,目录 revision 不变;显式 notify 必须重置已应用 revision
// 并强制重新应用,否则锁定列表会保持陈旧(上一条用例锁住「仅靠 focus 不会更新」)。
vi.mocked(loadClientLlmModels).mockResolvedValue({
defaultModelId: 'quality',
models: [
{ id: 'quality', displayName: '高质量', agentMode: 'codex' },
{ id: 'vision', displayName: '视觉', agentMode: 'codex' },
],
revision: 1,
});
act(() => notifyLlmConfigChanged());
await waitFor(() => expect(loadClientLlmModels).toHaveBeenCalledTimes(2));
fireEvent.click(screen.getByRole('button', { name: '对话模型' }));
await waitFor(() =>
expect(screen.getByRole('option', { name: '视觉' })).not.toBeNull(),
);
expect(screen.queryByRole('option', { name: '快速' })).toBeNull();
});