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 @@ -74,13 +74,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 @@ -178,8 +178,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 @@ -200,25 +201,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 font-mono", !isBot && "py-2 px-4")}>
<div className={cn("text-sm font-mono", 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 Down Expand Up @@ -252,7 +253,7 @@ export const Message = React.forwardRef<HTMLDivElement, MessageProps>(
</div>
</div>

{isBot ? null : avatar}
{(isBot || isSystem) ? null : avatar}
</div>
</div>
);
Expand Down
57 changes: 25 additions & 32 deletions components/frontend/src/components/ui/stream-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { ThinkingMessage } from "@/components/ui/thinking-message";
import { SystemMessage } from "@/components/ui/system-message";
import { Button } from "@/components/ui/button";
import { FeedbackButtons } from "@/components/feedback";

Check failure on line 10 in components/frontend/src/components/ui/stream-message.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

'FeedbackButtons' is defined but never used

export type StreamMessageProps = {
message: (MessageObject | ToolUseMessages | HierarchicalToolMessage) & { streaming?: boolean };
Expand Down Expand Up @@ -64,47 +64,40 @@
case "user_message":
case "agent_message": {
const isStreaming = 'streaming' in message && message.streaming;
const isAgent = m.type === "agent_message";

// Get content text for feedback context
const getContentText = () => {
if (typeof m.content === "string") return m.content;
if ("text" in m.content) return m.content.text;
if ("thinking" in m.content) return m.content.thinking;
return "";
};

// Feedback buttons for agent text messages (not tool use/result, not streaming)
const feedbackElement = isAgent && !isStreaming ? (
<FeedbackButtons
messageId={m.id} // Pass message ID for feedback association
messageContent={getContentText()}
messageTimestamp={m.timestamp}
/>
) : undefined;


// 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={isAgent ? "bot" : "user"}
content={m.content}
name="Claude AI"
borderless={plainCard}
timestamp={m.timestamp}
streaming={isStreaming}
feedbackButtons={feedbackElement}
/>
);
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={isAgent ? "bot" : "user"}
role={displayRole}
content={m.content.text}
name="Claude AI"
name={displayName}
borderless={plainCard}
timestamp={m.timestamp}
streaming={isStreaming}
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 @@ -106,7 +106,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 @@ -122,20 +122,36 @@ export type UserMessage = {
id?: string; // Message ID for feedback association
content: ContentBlock | string;
timestamp: string;
role?: "user"; // AG-UI role field
}
export type AgentMessage = {
type: "agent_message";
id?: string; // Message ID for feedback association
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