mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 18:30:44 +00:00
fix(control-ui): persist assistant avatar override locally (#71639)
* fix(control-ui): rebalance quick settings into stable 3-col bento Pair Appearance with Automations and let Channels stand alone in the middle column so all three top-row columns reach similar heights. Promote Personal to a full-width row with a horizontal body (identity tiles | emoji + actions) so the avatar block stops fighting for half-width space. Drops the unused .qs-stack--wide hook. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(control-ui): rebalance Personal card with symmetric User↔Assistant identity pair Restructure Personal card layout to present User and Assistant as 2 balanced identity cards instead of separate User tile + form controls. Mirrors the visual hierarchy and UI pattern across both identities. Changes: - Move User avatar text input into User identity card's .__repair section (mirroring Assistant's structure) - Inline "Choose image" and "Clear avatar" buttons as flex-wrapped action group - Remove .qs-personal-body and .qs-personal-form wrapper divs - Update Personal card's .qs-identity-grid to 2-column layout with balanced spacing - Responsive collapse to 1-column at ≤760px Tests: - config-quick.test.ts updated to expect 2 stacks (no longer wrapping Personal in form) - config-quick.test.ts validates identity card layout now has symmetric User↔Assistant structure - All 10 quick settings view tests passing - All 20 schema regression tests passing Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * chore: ignore .vmux worktree paths * fix(control-ui): persist assistant avatar override locally instead of via gateway config Mirrors the user-avatar pattern: assistant avatar uploads now go to localStorage and overlay the gateway-resolved identity at bootstrap and on agent.identity.get refreshes. Sidesteps the ui.assistant.avatar zod cap that rejected uploaded data URLs as 'Too big: expected string to have <=200 characters', removes one config.patch RPC from the avatar path, and collapses the upload handler from a 44-line async/loadConfig dance into a plain synchronous setter. Also lifts the gateway-side ui.assistant.avatar schema cap from 200 to 2,000,000 to match the user-avatar size budget for non-UI clients writing the field directly, and adds a content-aware text/image normalizer in ui/src/ui/assistant-identity.ts so short-text avatars stay short while data URLs survive round-tripping. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -878,7 +878,7 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = {
|
||||
},
|
||||
avatar: {
|
||||
type: "string",
|
||||
maxLength: 200,
|
||||
maxLength: 2000000,
|
||||
title: "Assistant Avatar",
|
||||
description:
|
||||
"Assistant avatar image source used in UI surfaces (URL, path, or data URI depending on runtime support). Use trusted assets and consistent branding dimensions for clean rendering.",
|
||||
|
||||
@@ -457,7 +457,7 @@ export const OpenClawSchema = z
|
||||
assistant: z
|
||||
.object({
|
||||
name: z.string().max(50).optional(),
|
||||
avatar: z.string().max(200).optional(),
|
||||
avatar: z.string().max(2_000_000).optional(),
|
||||
})
|
||||
.strict()
|
||||
.optional(),
|
||||
|
||||
@@ -40,4 +40,17 @@ describe("resolveAssistantIdentity avatar normalization", () => {
|
||||
|
||||
expect(resolveAssistantIdentity({ cfg, workspaceDir: "" }).avatar).toBe("avatars/openclaw.png");
|
||||
});
|
||||
|
||||
it("preserves long image data URLs without truncating past 200 chars", () => {
|
||||
const dataUrl = `data:image/png;base64,${"A".repeat(50_000)}`;
|
||||
const cfg: OpenClawConfig = {
|
||||
ui: {
|
||||
assistant: {
|
||||
avatar: dataUrl,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(resolveAssistantIdentity({ cfg, workspaceDir: "" }).avatar).toBe(dataUrl);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,7 +11,10 @@ import {
|
||||
} from "../shared/avatar-policy.js";
|
||||
|
||||
const MAX_ASSISTANT_NAME = 50;
|
||||
const MAX_ASSISTANT_AVATAR = 200;
|
||||
// Image-bearing avatars (data: URLs, paths) need to round-trip through
|
||||
// coerceIdentityValue without truncation. Sized to match
|
||||
// MAX_LOCAL_USER_IMAGE_AVATAR / AVATAR_MAX_BYTES expansion.
|
||||
const MAX_ASSISTANT_AVATAR = 2_000_000;
|
||||
const MAX_ASSISTANT_EMOJI = 16;
|
||||
|
||||
export const DEFAULT_ASSISTANT_IDENTITY: AssistantIdentity = {
|
||||
|
||||
Reference in New Issue
Block a user