diff --git a/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts b/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts index d95dabd72..63d8d9d82 100644 --- a/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts +++ b/apps/ai-game-creator-shell/src/features/app-shell/useAccountWallet.ts @@ -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; } diff --git a/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx b/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx index 6a4f2a067..2fcecb599 100644 --- a/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx +++ b/apps/ai-game-creator-shell/tests/conversationModelSelect.test.tsx @@ -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(); + 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(); +});