@@ -58,6 +58,34 @@ describe("loadAssistantIdentity", () => {
5858 sessionKey : "agent:worker:main" ,
5959 } ) ;
6060 } ) ;
61+
62+ it ( "applies a scoped identity request while its expected UI session remains active" , async ( ) => {
63+ const request = vi . fn ( ) . mockResolvedValue ( {
64+ agentId : "alpha" ,
65+ name : "Alpha" ,
66+ avatar : "A" ,
67+ } ) ;
68+ const state : Parameters < typeof loadAssistantIdentity > [ 0 ] = {
69+ client : { request } as never ,
70+ connected : true ,
71+ sessionKey : "main" ,
72+ assistantName : "Worker" ,
73+ assistantAvatar : null ,
74+ assistantAgentId : "worker" ,
75+ } ;
76+
77+ await loadAssistantIdentity ( state , {
78+ sessionKey : "agent:alpha:main" ,
79+ expectedSessionKey : "main" ,
80+ } ) ;
81+
82+ expect ( state . assistantName ) . toBe ( "Alpha" ) ;
83+ expect ( state . assistantAvatar ) . toBe ( "A" ) ;
84+ expect ( state . assistantAgentId ) . toBe ( "alpha" ) ;
85+ expect ( request ) . toHaveBeenCalledWith ( "agent.identity.get" , {
86+ sessionKey : "agent:alpha:main" ,
87+ } ) ;
88+ } ) ;
6189} ) ;
6290
6391describe ( "setAssistantAvatarOverride" , ( ) => {
@@ -71,13 +99,15 @@ describe("setAssistantAvatarOverride", () => {
7199 it ( "persists the assistant avatar locally and mirrors the user avatar pattern" , ( ) => {
72100 const state : Parameters < typeof setAssistantAvatarOverride > [ 0 ] = { } ;
73101
74- setAssistantAvatarOverride ( state , "data:image/png;base64,YXZhdGFy" ) ;
102+ setAssistantAvatarOverride ( state , "data:image/png;base64,YXZhdGFy" , "main" ) ;
75103
76104 expect ( state . assistantAvatar ) . toBe ( "data:image/png;base64,YXZhdGFy" ) ;
77105 expect ( state . assistantAvatarSource ) . toBe ( "data:image/png;base64,YXZhdGFy" ) ;
78106 expect ( state . assistantAvatarStatus ) . toBe ( "data" ) ;
79107 expect ( state . assistantAvatarReason ) . toBeNull ( ) ;
80- expect ( loadLocalAssistantIdentity ( ) . avatar ) . toBe ( "data:image/png;base64,YXZhdGFy" ) ;
108+ expect ( loadLocalAssistantIdentity ( { agentId : "main" } ) . avatar ) . toBe (
109+ "data:image/png;base64,YXZhdGFy" ,
110+ ) ;
81111 } ) ;
82112
83113 it ( "clears the local override" , ( ) => {
@@ -86,14 +116,58 @@ describe("setAssistantAvatarOverride", () => {
86116 assistantAvatarSource : "data:image/png;base64,YXZhdGFy" ,
87117 assistantAvatarStatus : "data" ,
88118 } ;
89- setAssistantAvatarOverride ( state , "data:image/png;base64,YXZhdGFy" ) ;
119+ setAssistantAvatarOverride ( state , "data:image/png;base64,YXZhdGFy" , "main" ) ;
90120
91- setAssistantAvatarOverride ( state , null ) ;
121+ setAssistantAvatarOverride ( state , null , "main" ) ;
92122
93123 expect ( state . assistantAvatar ) . toBeNull ( ) ;
94124 expect ( state . assistantAvatarSource ) . toBeNull ( ) ;
95125 expect ( state . assistantAvatarStatus ) . toBeNull ( ) ;
96126 expect ( state . assistantAvatarReason ) . toBeNull ( ) ;
97- expect ( loadLocalAssistantIdentity ( ) . avatar ) . toBeNull ( ) ;
127+ expect ( loadLocalAssistantIdentity ( { agentId : "main" } ) . avatar ) . toBeNull ( ) ;
128+ } ) ;
129+
130+ it ( "keeps assistant avatar overrides isolated by agent" , ( ) => {
131+ setAssistantAvatarOverride ( { } , "data:image/png;base64,bWFpbg==" , "main" ) ;
132+ setAssistantAvatarOverride ( { } , "data:image/png;base64,d29ya2Vy" , "worker" ) ;
133+
134+ expect ( loadLocalAssistantIdentity ( { agentId : "main" } ) . avatar ) . toBe (
135+ "data:image/png;base64,bWFpbg==" ,
136+ ) ;
137+ expect ( loadLocalAssistantIdentity ( { agentId : "worker" } ) . avatar ) . toBe (
138+ "data:image/png;base64,d29ya2Vy" ,
139+ ) ;
140+
141+ setAssistantAvatarOverride ( { } , null , "worker" ) ;
142+
143+ expect ( loadLocalAssistantIdentity ( { agentId : "main" } ) . avatar ) . toBe (
144+ "data:image/png;base64,bWFpbg==" ,
145+ ) ;
146+ expect ( loadLocalAssistantIdentity ( { agentId : "worker" } ) . avatar ) . toBeNull ( ) ;
147+ } ) ;
148+
149+ it ( "migrates the legacy global override to the first loaded agent" , ( ) => {
150+ localStorage . setItem (
151+ "openclaw.control.assistant.v1" ,
152+ JSON . stringify ( { avatar : "data:image/png;base64,bGVnYWN5" } ) ,
153+ ) ;
154+
155+ expect ( loadLocalAssistantIdentity ( { agentId : "main" } ) . avatar ) . toBe (
156+ "data:image/png;base64,bGVnYWN5" ,
157+ ) ;
158+ expect ( loadLocalAssistantIdentity ( { agentId : "worker" } ) . avatar ) . toBeNull ( ) ;
159+ } ) ;
160+
161+ it ( "supports prototype-like agent IDs without inherited avatar values" , ( ) => {
162+ setAssistantAvatarOverride ( { } , "data:image/png;base64,Y29uc3RydWN0b3I=" , "constructor" ) ;
163+ setAssistantAvatarOverride ( { } , "data:image/png;base64,cHJvdG8=" , "__proto__" ) ;
164+
165+ expect ( loadLocalAssistantIdentity ( { agentId : "constructor" } ) . avatar ) . toBe (
166+ "data:image/png;base64,Y29uc3RydWN0b3I=" ,
167+ ) ;
168+ expect ( loadLocalAssistantIdentity ( { agentId : "__proto__" } ) . avatar ) . toBe (
169+ "data:image/png;base64,cHJvdG8=" ,
170+ ) ;
171+ expect ( loadLocalAssistantIdentity ( { agentId : "toString" } ) . avatar ) . toBeNull ( ) ;
98172 } ) ;
99173} ) ;
0 commit comments