@@ -42,6 +42,7 @@ import {
4242import type { OpenClawConfig } from "../config/types.openclaw.js" ;
4343import { openBoundaryFileSync } from "../infra/boundary-file-read.js" ;
4444import {
45+ DEFAULT_AGENT_ID ,
4546 normalizeAgentId ,
4647 normalizeMainKey ,
4748 parseAgentSessionKey ,
@@ -414,22 +415,23 @@ export function resolveDeletedAgentIdFromSessionKey(
414415
415416export function loadSessionEntry ( sessionKey : string ) {
416417 const cfg = loadConfig ( ) ;
417- const canonicalKey = resolveSessionStoreKey ( { cfg, sessionKey } ) ;
418- const agentId = resolveSessionStoreAgentId ( cfg , canonicalKey ) ;
419- const { storePath, store } = resolveGatewaySessionStoreLookup ( {
420- cfg,
421- key : normalizeOptionalString ( sessionKey ) ?? "" ,
422- canonicalKey,
423- agentId,
424- } ) ;
418+ const key = normalizeOptionalString ( sessionKey ) ?? "" ;
425419 const target = resolveGatewaySessionStoreTarget ( {
426420 cfg,
427- key : normalizeOptionalString ( sessionKey ) ?? "" ,
428- store,
421+ key,
429422 } ) ;
423+ const storePath = target . storePath ;
424+ const store = loadSessionStore ( storePath ) ;
430425 const freshestMatch = resolveFreshestSessionStoreMatchFromStoreKeys ( store , target . storeKeys ) ;
431- const legacyKey = freshestMatch ?. key !== canonicalKey ? freshestMatch ?. key : undefined ;
432- return { cfg, storePath, store, entry : freshestMatch ?. entry , canonicalKey, legacyKey } ;
426+ const legacyKey = freshestMatch ?. key !== target . canonicalKey ? freshestMatch ?. key : undefined ;
427+ return {
428+ cfg,
429+ storePath,
430+ store,
431+ entry : freshestMatch ?. entry ,
432+ canonicalKey : target . canonicalKey ,
433+ legacyKey,
434+ } ;
433435}
434436
435437export function resolveFreshestSessionStoreMatchFromStoreKeys (
@@ -828,6 +830,83 @@ function resolveGatewaySessionStoreLookup(params: {
828830 } ;
829831}
830832
833+ function resolveExplicitDeletedLegacyMainStoreTarget ( params : {
834+ cfg : OpenClawConfig ;
835+ key : string ;
836+ scanLegacyKeys ?: boolean ;
837+ } ) : {
838+ agentId : string ;
839+ storePath : string ;
840+ canonicalKey : string ;
841+ storeKeys : string [ ] ;
842+ } | null {
843+ const parsed = parseAgentSessionKey ( params . key ) ;
844+ const legacyAgentId = normalizeAgentId ( parsed ?. agentId ) ;
845+ if (
846+ ! parsed ||
847+ legacyAgentId !== DEFAULT_AGENT_ID ||
848+ listAgentIds ( params . cfg ) . includes ( legacyAgentId )
849+ ) {
850+ return null ;
851+ }
852+
853+ // Only preserve agent:main:* when it is backed by a discovered deleted-main store.
854+ // Shared-store legacy aliases should continue remapping to the configured default agent.
855+ const canonicalKey = resolveStoredSessionKeyForAgentStore ( {
856+ cfg : params . cfg ,
857+ agentId : legacyAgentId ,
858+ sessionKey : params . key ,
859+ } ) ;
860+ const agentMainKey = resolveAgentMainSessionKey ( { cfg : params . cfg , agentId : legacyAgentId } ) ;
861+ const legacyAgentMainKey = `agent:${ legacyAgentId } :main` ;
862+ const lookupSeeds = Array . from (
863+ new Set ( [ params . key , canonicalKey , agentMainKey , legacyAgentMainKey ] ) ,
864+ ) ;
865+ let best :
866+ | {
867+ storePath : string ;
868+ store : Record < string , SessionEntry > ;
869+ match : { entry : SessionEntry ; key : string } ;
870+ }
871+ | undefined ;
872+ for ( const target of resolveAllAgentSessionStoreTargetsSync ( params . cfg ) ) {
873+ if ( target . agentId !== legacyAgentId ) {
874+ continue ;
875+ }
876+ const store = loadSessionStore ( target . storePath ) ;
877+ const match = findFreshestStoreMatch ( store , ...lookupSeeds ) ;
878+ if ( ! match ) {
879+ continue ;
880+ }
881+ if ( ! best || ( match . entry . updatedAt ?? 0 ) >= ( best . match . entry . updatedAt ?? 0 ) ) {
882+ best = { storePath : target . storePath , store, match } ;
883+ }
884+ }
885+ if ( ! best ) {
886+ return null ;
887+ }
888+
889+ const storeKeys = new Set < string > ( [ canonicalKey ] ) ;
890+ if ( params . key !== canonicalKey ) {
891+ storeKeys . add ( params . key ) ;
892+ }
893+ storeKeys . add ( best . match . key ) ;
894+ if ( params . scanLegacyKeys !== false ) {
895+ for ( const seed of lookupSeeds ) {
896+ storeKeys . add ( seed ) ;
897+ for ( const legacyKey of findStoreKeysIgnoreCase ( best . store , seed ) ) {
898+ storeKeys . add ( legacyKey ) ;
899+ }
900+ }
901+ }
902+ return {
903+ agentId : legacyAgentId ,
904+ storePath : best . storePath ,
905+ canonicalKey,
906+ storeKeys : Array . from ( storeKeys ) ,
907+ } ;
908+ }
909+
831910export function resolveGatewaySessionStoreTarget ( params : {
832911 cfg : OpenClawConfig ;
833912 key : string ;
@@ -840,6 +919,15 @@ export function resolveGatewaySessionStoreTarget(params: {
840919 storeKeys : string [ ] ;
841920} {
842921 const key = normalizeOptionalString ( params . key ) ?? "" ;
922+ const explicitDeletedMainTarget = resolveExplicitDeletedLegacyMainStoreTarget ( {
923+ cfg : params . cfg ,
924+ key,
925+ scanLegacyKeys : params . scanLegacyKeys ,
926+ } ) ;
927+ if ( explicitDeletedMainTarget ) {
928+ return explicitDeletedMainTarget ;
929+ }
930+
843931 const canonicalKey = resolveSessionStoreKey ( {
844932 cfg : params . cfg ,
845933 sessionKey : key ,
0 commit comments