openclaw - ✅(Solved) Fix [Bug]: Control UI Chat shows default agent identity for all agent sessions (race condition) [1 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#72516Fetched 2026-04-28 06:35:03
View on GitHub
Comments
2
Participants
3
Timeline
5
Reactions
0
Author
Timeline (top)
commented ×2cross-referenced ×2closed ×1

When navigating to a non-default agent session in Control UI Chat (e.g. ?session=agent%3Alottery%3Amain), the message bubble sidebar always shows the default agent name and emoji instead of the correct agent identity.

Example:

  • URL: http://127.0.0.1:18789/chat?session=agent%3Alottery%3Amain (agent "旺财🐕")
  • Expected: Message bubbles show "旺财" with 🐕
  • Actual: Message bubbles show "傻狗" with 🐶 (default agent identity)

This affects ALL non-default agents. The backend agent.identity.get API returns correct identity data — the issue is purely in the Control UI frontend.

Root Cause

The issue is a race condition between two async identity-fetching functions in the Control UI initialization:

  1. AN(e) — HTTP GET to /__openclaw/control-ui-config.json

    • This endpoint always returns the default agent identity (hardcoded at server startup)
    • Response: {"assistantName":"傻狗","assistantAvatar":"🐶","assistantAgentId":"main"}
  2. ON(e) — WebSocket call to agent.identity.get with the current sessionKey

    • This correctly returns the identity for the requested agent session
    • e.g. {"name":"旺财","avatar":"🐕","agentId":"lottery"}

Both functions write to the same global state:

e.assistantName = o.name;
e.assistantAvatar = o.avatar;
e.assistantAgentId = o.agentId ?? null;

If AN() (HTTP fetch) resolves after ON() (WebSocket RPC), it overwrites the correct identity with the default agent's identity. Since HTTP latency can vary, this race condition causes inconsistent behavior.

Fix Action

Fixed

PR fix notes

PR #72579: Fix: Issue 72516 control UI agent identity

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem: Control UI Chat could show the default agent identity for non-default agent sessions such as agent:lottery:main.
  • Why it matters: Users can be misled about which agent they are chatting with in multi-agent setups.
  • What changed: Non-default agent identity now prefers agents.list[].identity; Control UI guards bootstrap/session identity races; avatar resolution no follows the same default vs non-default precedence.
  • What did NOT change (scope boundary): No broad Control UI state refactor, no generated locale changes, no plugin/runtime behavior changes, and no remote PR automation.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #72516
  • Related #54714
  • This PR fixes a bug or regression

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause: The backend identity resolver preferred global ui.assistant values before per-agent identity for every agent, and the Control UI bootstrap and session-specific identity loaders could both write the same global Chat identity fields in either order.
  • Missing detection / guardrail: No regression coverage for non-default agent.identity.get, bootstrap resolving after session identity, or avatar metadata/ server precedence for non-default agents.
  • Contributing context (if known): The bootstrap endpoint is default-agent oriented, while Chat can be opened directly on a non-default session URL.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
    • Target test or file: src/gateway/assistant-identity.test.ts, src/agents/identity-avatar.test.ts, src/gateway/server-methods/agent.test.ts, ui/src/ui/ controllers/assistant-identity.test.ts, ui/src/ui/controllers/control-ui-bootstrap.test.ts, ui/src/ui/app-gateway.node.test.ts
    • Scenario the test should lock in: Non-default sessions keep their own name/avatar even when global ui.assistant and bootstrap default identity are present.
    • Why this is the smallest reliable guardrail: It covers the resolver, RPC seam, and Control UI race guards without requiring a full browser E2E.
    • Existing test that already covers this (if any): None.
    • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Control UI Chat now shows the selected non-default agent identity instead of being overwritten by the default agent identity during bootstrap or reconnect races.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

  Before:
  [open /chat?session=agent:lottery:main]
    -> [agent.identity.get returns session identity]
    -> [bootstrap may resolve later]
    -> [default identity overwrites Chat]

  After:
  [open /chat?session=agent:lottery:main]
    -> [agent.identity.get returns session identity]
    -> [bootstrap default identity is ignored for mismatched active agent]
    -> [Chat keeps lottery identity]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local source checkout, Node/pnpm workspace
  • Model/provider: N/A
  • Integration/channel (if any): Control UI Chat
  • Relevant config (redacted): multi-agent config with global ui.assistant and a non-default agent identity

Steps

  1. Configure at least two agents with distinct identities.
  2. Open Control UI Chat directly to a non-default session such as /chat?session=agent%3Alottery%3Amain.
  3. Let bootstrap and WebSocket identity loading complete in either order.

Expected

  • Chat displays the non-default agent identity.

Actual

  • Before this fix, Chat could display the default/global assistant identity.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • Non-default backend identity precedence.
    • agent.identity.get returns selected non-default agent identity.
    • Bootstrap does not overwrite active non-default Chat identity.
    • Explicit agent:main:main does not get treated as default when bootstrap identity belongs to another configured default agent.
    • Avatar resolver matches non-default identity precedence.
  • Edge cases checked:
    • Default agent still preserves global ui.assistant priority.
    • Stale implicit session identity results are ignored after session changes.
    • Explicit session-key identity loads still apply.
  • What you did not verify:
    • Manual browser screenshot/recording.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: Existing users may expect global ui.assistant to override every agent identity.
    • Mitigation: The global override is preserved for the configured default agent; only non-default agents now prefer their own configured identity.
  • Risk: One Codex review P3 remains intentionally unfixed: local browser assistant avatar override is not applied during bootstrap when server identity writes are skipped for a mismatched non-default active session.
    • Mitigation: This preserves the requested narrower scope; WebSocket session identity still applies after connect.

Built with Codex

Changed files

  • src/agents/identity-avatar.test.ts (modified, +57/-0)
  • src/agents/identity-avatar.ts (modified, +11/-11)
  • src/gateway/assistant-identity.test.ts (modified, +89/-0)
  • src/gateway/assistant-identity.ts (modified, +29/-12)
  • src/gateway/server-methods/agent.test.ts (modified, +41/-0)
  • src/plugins/cli-registry-loader.ts (modified, +2/-1)
  • src/plugins/cli.test.ts (modified, +75/-0)
  • ui/src/ui/app-gateway.node.test.ts (modified, +2/-1)
  • ui/src/ui/controllers/assistant-identity.test.ts (modified, +128/-1)
  • ui/src/ui/controllers/assistant-identity.ts (modified, +3/-0)
  • ui/src/ui/controllers/control-ui-bootstrap.test.ts (modified, +125/-0)
  • ui/src/ui/controllers/control-ui-bootstrap.ts (modified, +23/-13)

Code Example

e.assistantName = o.name;
e.assistantAvatar = o.avatar;
e.assistantAgentId = o.agentId ?? null;
RAW_BUFFERClick to expand / collapse

Bug type

Regression / Race condition

Summary

When navigating to a non-default agent session in Control UI Chat (e.g. ?session=agent%3Alottery%3Amain), the message bubble sidebar always shows the default agent name and emoji instead of the correct agent identity.

Example:

  • URL: http://127.0.0.1:18789/chat?session=agent%3Alottery%3Amain (agent "旺财🐕")
  • Expected: Message bubbles show "旺财" with 🐕
  • Actual: Message bubbles show "傻狗" with 🐶 (default agent identity)

This affects ALL non-default agents. The backend agent.identity.get API returns correct identity data — the issue is purely in the Control UI frontend.

Root Cause Analysis

The issue is a race condition between two async identity-fetching functions in the Control UI initialization:

  1. AN(e) — HTTP GET to /__openclaw/control-ui-config.json

    • This endpoint always returns the default agent identity (hardcoded at server startup)
    • Response: {"assistantName":"傻狗","assistantAvatar":"🐶","assistantAgentId":"main"}
  2. ON(e) — WebSocket call to agent.identity.get with the current sessionKey

    • This correctly returns the identity for the requested agent session
    • e.g. {"name":"旺财","avatar":"🐕","agentId":"lottery"}

Both functions write to the same global state:

e.assistantName = o.name;
e.assistantAvatar = o.avatar;
e.assistantAgentId = o.agentId ?? null;

If AN() (HTTP fetch) resolves after ON() (WebSocket RPC), it overwrites the correct identity with the default agent's identity. Since HTTP latency can vary, this race condition causes inconsistent behavior.

Steps to Reproduce

  1. Configure multiple agents with distinct identities (name, emoji)
  2. Open Control UI and navigate to a non-default agent session: /chat?session=agent%3A<non-default-agent>%3Amain
  3. Observe the assistant name next to message bubbles — it shows the default agent's name/emoji

Expected Behavior

Each agent session should display its own configured identity (name, avatar/emoji) in the chat message bubbles.

Suggested Fix

In AN(e), skip overwriting assistantName/assistantAvatar/assistantAgentId if the current session belongs to a non-default agent, OR ensure ON(e) always runs after AN(e) to guarantee the session-specific identity takes precedence.

Alternatively, AN() could check if the current sessionKey resolves to a different agent than the one returned by the config endpoint, and skip the identity update in that case.

Environment

  • OpenClaw version: 2026.4.24
  • OS: macOS (arm64)
  • Browser: Chrome
  • 4 configured agents with distinct identities

Related

  • #54714 (similar but for Agents management page, not Chat page)

extent analysis

TL;DR

Modify the AN(e) function to conditionally update the global state based on the current session key to prevent overwriting the correct agent identity.

Guidance

  • Verify that the ON(e) WebSocket call is correctly retrieving the agent identity for the requested session by checking the response data.
  • Update the AN(e) function to check if the current session belongs to a non-default agent before updating the assistantName, assistantAvatar, and assistantAgentId global state variables.
  • Consider adding a mechanism to ensure ON(e) always runs after AN(e) to guarantee the session-specific identity takes precedence.
  • Test the changes with multiple agents and session configurations to ensure the fix works as expected.

Example

// Example modification to AN(e) function
if (sessionKey !== 'default') {
  // Skip updating global state if not default agent
  return;
}
e.assistantName = o.name;
e.assistantAvatar = o.avatar;
e.assistantAgentId = o.agentId ?? null;

Notes

The provided fix assumes that the sessionKey variable is accessible within the AN(e) function. If not, additional modifications may be necessary to pass the required information.

Recommendation

Apply the suggested workaround by modifying the AN(e) function to conditionally update the global state, as this approach directly addresses the identified race condition issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Control UI Chat shows default agent identity for all agent sessions (race condition) [1 pull requests, 2 comments, 3 participants]