feat: add avatar support for agent identity
- Add avatar field to IdentityConfig type - Add avatar parsing in AgentIdentity from IDENTITY.md - Add renderAvatar support for image avatars in webchat - Add CSS styling for image avatars Users can now configure a custom avatar for the assistant in the webchat by setting 'identity.avatar' in the agent config or adding 'Avatar: path' to IDENTITY.md. The avatar can be served from the assets folder. Closes #TBD
This commit is contained in:
@@ -34,6 +34,7 @@ export type AgentIdentity = {
|
|||||||
creature?: string;
|
creature?: string;
|
||||||
vibe?: string;
|
vibe?: string;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
|
avatar?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function listAgentEntries(cfg: ClawdbotConfig): AgentEntry[] {
|
export function listAgentEntries(cfg: ClawdbotConfig): AgentEntry[] {
|
||||||
@@ -90,6 +91,7 @@ export function parseIdentityMarkdown(content: string): AgentIdentity {
|
|||||||
if (label === "creature") identity.creature = value;
|
if (label === "creature") identity.creature = value;
|
||||||
if (label === "vibe") identity.vibe = value;
|
if (label === "vibe") identity.vibe = value;
|
||||||
if (label === "theme") identity.theme = value;
|
if (label === "theme") identity.theme = value;
|
||||||
|
if (label === "avatar") identity.avatar = value;
|
||||||
}
|
}
|
||||||
return identity;
|
return identity;
|
||||||
}
|
}
|
||||||
@@ -99,7 +101,7 @@ export function loadAgentIdentity(workspace: string): AgentIdentity | null {
|
|||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(identityPath, "utf-8");
|
const content = fs.readFileSync(identityPath, "utf-8");
|
||||||
const parsed = parseIdentityMarkdown(content);
|
const parsed = parseIdentityMarkdown(content);
|
||||||
if (!parsed.name && !parsed.emoji && !parsed.theme && !parsed.creature && !parsed.vibe) {
|
if (!parsed.name && !parsed.emoji && !parsed.theme && !parsed.creature && !parsed.vibe && !parsed.avatar) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return parsed;
|
return parsed;
|
||||||
|
|||||||
@@ -144,4 +144,6 @@ export type IdentityConfig = {
|
|||||||
name?: string;
|
name?: string;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
|
/** Path to a custom avatar image (relative to workspace or absolute). */
|
||||||
|
avatar?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,6 +89,12 @@
|
|||||||
color: rgba(134, 142, 150, 1);
|
color: rgba(134, 142, 150, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Image avatar support */
|
||||||
|
img.chat-avatar {
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* Minimal Bubble Design - dynamic width based on content */
|
/* Minimal Bubble Design - dynamic width based on content */
|
||||||
.chat-bubble {
|
.chat-bubble {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export function renderMessageGroup(
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAvatar(role: string) {
|
function renderAvatar(role: string, avatarUrl?: string) {
|
||||||
const normalized = normalizeRoleForGrouping(role);
|
const normalized = normalizeRoleForGrouping(role);
|
||||||
const initial =
|
const initial =
|
||||||
normalized === "user"
|
normalized === "user"
|
||||||
@@ -122,6 +122,12 @@ function renderAvatar(role: string) {
|
|||||||
: normalized === "tool"
|
: normalized === "tool"
|
||||||
? "tool"
|
? "tool"
|
||||||
: "other";
|
: "other";
|
||||||
|
|
||||||
|
// If avatar URL is provided for assistant, show image
|
||||||
|
if (avatarUrl && normalized === "assistant") {
|
||||||
|
return html`<img class="chat-avatar ${className}" src="${avatarUrl}" alt="Assistant" />`;
|
||||||
|
}
|
||||||
|
|
||||||
return html`<div class="chat-avatar ${className}">${initial}</div>`;
|
return html`<div class="chat-avatar ${className}">${initial}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user