Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions components/frontend/src/components/session/MessagesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,17 @@ const MessagesTab: React.FC<MessagesTabProps> = ({ session, streamMessages, chat
// Filter out system messages unless showSystemMessages is true
const filteredMessages = streamMessages.filter((msg) => {
if (showSystemMessages) return true;

// Hide system_message type by default
// Check if msg has a type property and if it's a system_message

// Hide system_message type by default (legacy)
if ('type' in msg && msg.type === "system_message") {
return false;
}


// Hide messages with system or developer role (AG-UI protocol)
if ('role' in msg && (msg.role === "system" || msg.role === "developer")) {
return false;
}

return true;
});

Expand Down
23 changes: 12 additions & 11 deletions components/frontend/src/components/ui/message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import remarkGfm from "remark-gfm";
import type { Components } from "react-markdown";
import { formatTimestamp } from "@/lib/format-timestamp";

export type MessageRole = "bot" | "user";
export type MessageRole = "bot" | "user" | "system";

export type MessageProps = {
role: MessageRole;
Expand Down Expand Up @@ -176,8 +176,9 @@ export const Message = React.forwardRef<HTMLDivElement, MessageProps>(
ref
) => {
const isBot = role === "bot";
const avatarBg = isBot ? "bg-blue-600" : "bg-green-600";
const avatarText = isBot ? "AI" : "U";
const isSystem = role === "system";
const avatarBg = isBot ? "bg-blue-600" : isSystem ? "bg-gray-500" : "bg-green-600";
const avatarText = isBot ? "AI" : isSystem ? "SYS" : "U";
const formattedTime = formatTimestamp(timestamp);
const isActivelyStreaming = streaming && isBot;

Expand All @@ -198,25 +199,25 @@ export const Message = React.forwardRef<HTMLDivElement, MessageProps>(
)

return (
<div ref={ref} className={cn("mb-4", isBot && "mt-2", className)} {...props}>
<div className={cn("flex space-x-3", isBot ? "items-start" : "items-center justify-end")}>
<div ref={ref} className={cn("mb-4", (isBot || isSystem) && "mt-2", className)} {...props}>
<div className={cn("flex space-x-3", (isBot || isSystem) ? "items-start" : "items-center justify-end")}>
{/* Avatar */}
{isBot ? avatar : null}
{(isBot || isSystem) ? avatar : null}

{/* Message Content */}
<div className={cn("flex-1 min-w-0", !isBot && "max-w-[70%]")}>
<div className={cn("flex-1 min-w-0", (!isBot && !isSystem) && "max-w-[70%]")}>
{/* Timestamp */}
{formattedTime && (
<div className={cn("text-[10px] text-muted-foreground/60 mb-1", !isBot && "text-right")}>
<div className={cn("text-[10px] text-muted-foreground/60 mb-1", (!isBot && !isSystem) && "text-right")}>
{formattedTime}
</div>
)}
<div className={cn(
borderless ? "p-0" : "rounded-lg",
!borderless && (isBot ? "bg-card" : "bg-border/30")
!borderless && ((isBot || isSystem) ? isSystem ? "bg-muted/50" : "bg-card" : "bg-border/30")
)}>
{/* Content */}
<div className={cn("text-sm text-foreground", !isBot && "py-2 px-4")}>
<div className={cn("text-sm", isSystem ? "text-muted-foreground" : "text-foreground", (!isBot && !isSystem) && "py-2 px-4")}>
{isLoading ? (
<div>
<div className="text-sm text-muted-foreground mb-2">{content}</div>
Expand All @@ -243,7 +244,7 @@ export const Message = React.forwardRef<HTMLDivElement, MessageProps>(
</div>
</div>

{isBot ? null : avatar}
{(isBot || isSystem) ? null : avatar}
</div>
</div>
);
Expand Down
26 changes: 24 additions & 2 deletions components/frontend/src/components/ui/stream-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,36 @@ export const StreamMessage: React.FC<StreamMessageProps> = ({ message, onGoToRes
case "user_message":
case "agent_message": {
const isStreaming = 'streaming' in message && message.streaming;

// Check for AG-UI role field
const role = 'role' in m ? m.role : undefined;

// Determine display role based on AG-UI role
let displayRole: "user" | "bot" | "system" = "user";
let displayName = "You";

if (role === "assistant" || (m.type === "agent_message" && !role)) {
displayRole = "bot";
displayName = "Claude AI";
} else if (role === "developer") {
displayRole = "system";
displayName = "Platform";
} else if (role === "system") {
displayRole = "system";
displayName = "System";
} else if (role === "user" || m.type === "user_message") {
displayRole = "user";
displayName = "You";
}

if (typeof m.content === "string") {
return <Message role={m.type === "agent_message" ? "bot" : "user"} content={m.content} name="Claude AI" borderless={plainCard} timestamp={m.timestamp} streaming={isStreaming}/>;
return <Message role={displayRole} content={m.content} name={displayName} borderless={plainCard} timestamp={m.timestamp} streaming={isStreaming}/>;
}
switch (m.content.type) {
case "thinking_block":
return <ThinkingMessage block={m.content} />
case "text_block":
return <Message role={m.type === "agent_message" ? "bot" : "user"} content={m.content.text} name="Claude AI" borderless={plainCard} timestamp={m.timestamp} streaming={isStreaming}/>
return <Message role={displayRole} content={m.content.text} name={displayName} borderless={plainCard} timestamp={m.timestamp} streaming={isStreaming}/>
case "tool_use_block":
return <ToolMessage toolUseBlock={m.content} borderless={plainCard}/>
case "tool_result_block":
Expand Down
18 changes: 17 additions & 1 deletion components/frontend/src/types/agentic-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export type HierarchicalToolMessage = ToolUseMessages & {
// -----------------------------
// Message Types
// -----------------------------
export type Message = UserMessage | AgentMessage | SystemMessage | ResultMessage | ToolUseMessages | AgentRunningMessage | AgentWaitingMessage;
export type Message = UserMessage | AgentMessage | SystemMessage | ResultMessage | ToolUseMessages | AgentRunningMessage | AgentWaitingMessage | DeveloperMessage | SystemRoleMessage;

export type AgentRunningMessage = {
type: "agent_running";
Expand All @@ -117,19 +117,35 @@ export type UserMessage = {
type: "user_message";
content: ContentBlock | string;
timestamp: string;
role?: "user"; // AG-UI role field
}
export type AgentMessage = {
type: "agent_message";
content: ContentBlock;
model: string;
timestamp: string;
role?: "assistant"; // AG-UI role field
}
// Legacy system_message type (for compatibility)
export type SystemMessage = {
type: "system_message";
subtype: string;
data: Record<string, unknown>;
timestamp: string;
}
// New AG-UI role-based messages
export type DeveloperMessage = {
type: "user_message" | "agent_message";
content: ContentBlock | string;
timestamp: string;
role: "developer"; // Platform/internal logging
}
export type SystemRoleMessage = {
type: "user_message" | "agent_message";
content: ContentBlock | string;
timestamp: string;
role: "system"; // Claude system messages (turn info, etc)
}
export type ResultMessage = {
type: "result_message";
subtype: string;
Expand Down
Loading
Loading