@@ -35,6 +35,7 @@ import {
3535 velaWalletSnapshotReader ,
3636} from '../integrations/vela-wallet.js' ;
3737import { amrModelLoadingCache } from '../runtimes/amr-model-cache.js' ;
38+ import { buildAmrModelCacheKey } from '../runtimes/amr-model-probe.js' ;
3839import {
3940 fetchVelaBillingSummary ,
4041 fetchVelaPresetModels ,
@@ -169,14 +170,9 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
169170 agentLaunch ,
170171 ) ;
171172 const credentialRevision = readVelaCredentialRevision ( env , configuredEnv ) ;
172- const cacheKey = JSON . stringify ( {
173+ const cacheKey = buildAmrModelCacheKey ( {
173174 launchPath,
174- home : spawnEnv . HOME ?? spawnEnv . USERPROFILE ?? '' ,
175- openDesignAmrProfile : spawnEnv . OPEN_DESIGN_AMR_PROFILE ?? '' ,
176- velaProfile : spawnEnv . VELA_PROFILE ?? '' ,
177- velaLinkUrl : spawnEnv . VELA_LINK_URL ?? '' ,
178- velaRuntimeKey : spawnEnv . VELA_RUNTIME_KEY ?? '' ,
179- velaOpencodeBin : spawnEnv . VELA_OPENCODE_BIN ?? '' ,
175+ env : spawnEnv ,
180176 credentialRevision,
181177 } ) ;
182178 return { launchPath, env : spawnEnv , configuredEnv, cacheKey } ;
@@ -197,17 +193,29 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
197193 string ,
198194 Promise < VelaLiveAccount | null >
199195 > ( ) ;
196+ const inFlightVelaAccountInvalidations = new Set < string > ( ) ;
200197 function fetchVelaLiveAccountSingleFlight (
201198 accountCacheKey : string ,
202199 probe : AmrModelProbe ,
200+ options : { invalidateModelsOnPlanChange ?: boolean } = { } ,
203201 ) : Promise < VelaLiveAccount | null > {
202+ if ( options . invalidateModelsOnPlanChange === true ) {
203+ inFlightVelaAccountInvalidations . add ( accountCacheKey ) ;
204+ }
204205 const existing = inFlightVelaAccountFetches . get ( accountCacheKey ) ;
205206 if ( existing ) return existing ;
206207 const pending = ( async ( ) => {
208+ const previousAccount = peekVelaLiveAccount ( accountCacheKey ) ;
207209 amrModelLoadingCache . warm ( probe . cacheKey , ( ) =>
208210 fetchVelaRemoteModelsWithRetry ( probe . launchPath , probe . env ) ,
209211 ) ;
210212 const account = await fetchVelaBillingSummary ( probe . launchPath , probe . env ) ;
213+ if (
214+ inFlightVelaAccountInvalidations . has ( accountCacheKey ) &&
215+ ( ! previousAccount || previousAccount . plan !== account . plan )
216+ ) {
217+ amrModelLoadingCache . invalidate ( probe . cacheKey ) ;
218+ }
211219 setVelaLiveAccount ( accountCacheKey , account ) ;
212220 return account ;
213221 } ) ( )
@@ -220,6 +228,7 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
220228 } )
221229 . finally ( ( ) => {
222230 inFlightVelaAccountFetches . delete ( accountCacheKey ) ;
231+ inFlightVelaAccountInvalidations . delete ( accountCacheKey ) ;
223232 } ) ;
224233 inFlightVelaAccountFetches . set ( accountCacheKey , pending ) ;
225234 return pending ;
@@ -242,6 +251,7 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
242251 try {
243252 const appConfig = await readAppConfig ( RUNTIME_DATA_DIR ) ;
244253 const configuredEnv = agentCliEnvForAgent ( appConfig . agentCliEnv , 'amr' ) ;
254+ const refresh = _req . query . refresh === '1' || _req . query . refresh === 'true' ;
245255 const status = readVelaLoginStatus ( mergeVelaEnv ( env , configuredEnv ) ) ;
246256 if ( status . loggedIn ) {
247257 // Key the live-account cache by the full credential revision (not just
@@ -254,7 +264,12 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
254264 ) ;
255265 const probe = resolveAmrModelProbeForEnv ( configuredEnv ) ;
256266 const cachedAccount = peekVelaLiveAccount ( accountCacheKey ) ;
257- if ( ! cachedAccount ) {
267+ if ( refresh ) {
268+ const liveAccount = await fetchVelaLiveAccountSingleFlight ( accountCacheKey , probe , {
269+ invalidateModelsOnPlanChange : true ,
270+ } ) ;
271+ applyVelaLiveAccount ( status , liveAccount ) ;
272+ } else if ( ! cachedAccount ) {
258273 // Cold cache (or a fetch already in flight): BLOCK on the single-flight
259274 // billing fetch so the first open already carries plan/balance. The
260275 // consumers (settings card, inline switcher, avatar) read /status once
@@ -274,7 +289,9 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
274289 // next poll once the TTL has lapsed.
275290 applyVelaLiveAccount ( status , cachedAccount ) ;
276291 if ( shouldRefreshVelaLiveAccount ( accountCacheKey ) ) {
277- void fetchVelaLiveAccountSingleFlight ( accountCacheKey , probe ) . catch ( ( ) => { } ) ;
292+ void fetchVelaLiveAccountSingleFlight ( accountCacheKey , probe , {
293+ invalidateModelsOnPlanChange : true ,
294+ } ) . catch ( ( ) => { } ) ;
278295 }
279296 }
280297 }
@@ -294,6 +311,14 @@ export function registerVelaRoutes(app: Express, deps: RegisterVelaRoutesDeps):
294311 configuredEnv,
295312 refresh,
296313 } ) ;
314+ if ( refresh ) {
315+ try {
316+ const modelProbe = resolveAmrModelProbeForEnv ( configuredEnv ) ;
317+ amrModelLoadingCache . invalidate ( modelProbe . cacheKey ) ;
318+ } catch ( err ) {
319+ console . warn ( '[amr] model cache invalidation after wallet refresh failed' , err ) ;
320+ }
321+ }
297322 res . json ( snapshot ) ;
298323 } catch ( err ) {
299324 res . status ( 500 ) . json ( { error : String ( err ) } ) ;
0 commit comments