- Updated TeamProvisioningService to include subagent type in spawn messages for clarity. - Improved member registration checks to account for suffixed names, enhancing error handling. - Refactored SubagentRecentMessagesPreview to strip agent-only blocks from messages, improving display clarity. - Adjusted tests to reflect changes in message formatting and member provisioning logic.
125 lines
4.4 KiB
TypeScript
125 lines
4.4 KiB
TypeScript
import { useMemo, useState } from 'react';
|
|
|
|
import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer';
|
|
import { displayMemberName } from '@renderer/utils/memberHelpers';
|
|
import { stripAgentBlocks } from '@shared/constants/agentBlocks';
|
|
import { format } from 'date-fns';
|
|
import { ChevronDown, ChevronUp } from 'lucide-react';
|
|
|
|
export type SubagentPreviewMessageKind =
|
|
| 'output'
|
|
| 'text'
|
|
| 'tool_result'
|
|
| 'interruption'
|
|
| 'plan_exit'
|
|
| 'teammate_message'
|
|
| 'user'
|
|
| 'unknown';
|
|
|
|
export interface SubagentPreviewMessage {
|
|
id: string;
|
|
timestamp: Date;
|
|
kind: SubagentPreviewMessageKind;
|
|
/** Optional short label (e.g. tool name). */
|
|
label?: string;
|
|
content: string;
|
|
}
|
|
|
|
interface SubagentRecentMessagesPreviewProps {
|
|
messages: SubagentPreviewMessage[];
|
|
memberName?: string;
|
|
hasMore?: boolean;
|
|
onLoadMore?: () => void;
|
|
}
|
|
|
|
export const SubagentRecentMessagesPreview = ({
|
|
messages,
|
|
memberName,
|
|
hasMore = false,
|
|
onLoadMore,
|
|
}: SubagentRecentMessagesPreviewProps): React.JSX.Element | null => {
|
|
const [expandedAll, setExpandedAll] = useState(false);
|
|
|
|
// Strip agent-only blocks from message content before display
|
|
const cleanMessages = useMemo(
|
|
() =>
|
|
messages
|
|
.map((m) => {
|
|
const cleaned = stripAgentBlocks(m.content);
|
|
return cleaned !== m.content ? { ...m, content: cleaned } : m;
|
|
})
|
|
.filter((m) => m.content.trim().length > 0),
|
|
[messages]
|
|
);
|
|
|
|
if (!cleanMessages.length) return null;
|
|
|
|
return (
|
|
<div className="mb-3 rounded-md border border-[var(--color-border)] bg-[var(--color-surface)] p-2">
|
|
<div className="mb-2 flex items-center gap-2">
|
|
<div className="min-w-0 truncate text-[11px] text-[var(--color-text-muted)]">
|
|
Latest messages{memberName ? ` — ${displayMemberName(memberName)}` : ''}
|
|
</div>
|
|
</div>
|
|
|
|
<div className={`${expandedAll ? 'max-h-none' : 'max-h-[200px]'} overflow-y-auto pr-1`}>
|
|
{cleanMessages.map((m, index) => (
|
|
<div
|
|
key={m.id}
|
|
className="rounded px-2 py-1.5"
|
|
style={index % 2 === 0 ? { backgroundColor: 'var(--card-bg-zebra)' } : undefined}
|
|
>
|
|
<div className="flex items-start gap-2">
|
|
<div className="min-w-0 flex-1 text-xs text-[var(--color-text)]">
|
|
<MarkdownViewer
|
|
content={m.content}
|
|
bare
|
|
maxHeight="max-h-none"
|
|
className="[&>div>div]:p-0 [&_ol]:my-1 [&_p]:my-1 [&_ul]:my-1"
|
|
/>
|
|
</div>
|
|
<div className="shrink-0 text-right text-[10px] text-[var(--color-text-muted)]">
|
|
{format(m.timestamp, 'h:mm:ss a')}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
|
|
{hasMore && onLoadMore ? (
|
|
<div className="flex justify-center pb-1 pt-2">
|
|
<button
|
|
type="button"
|
|
className="flex items-center gap-1 rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] px-2.5 py-1 text-[11px] text-[var(--color-text-muted)] shadow-sm transition-colors hover:bg-[var(--color-surface)] hover:text-[var(--color-text-secondary)]"
|
|
onClick={onLoadMore}
|
|
>
|
|
<ChevronDown size={12} />
|
|
Load more
|
|
</button>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
|
|
<div className="sticky bottom-0 z-10 flex justify-end pb-1 pt-2">
|
|
{!expandedAll ? (
|
|
<button
|
|
type="button"
|
|
className="flex items-center gap-1 rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] px-2.5 py-1 text-[11px] text-[var(--color-text-muted)] shadow-sm transition-colors hover:bg-[var(--color-surface)] hover:text-[var(--color-text-secondary)]"
|
|
onClick={() => setExpandedAll(true)}
|
|
>
|
|
<ChevronDown size={12} />
|
|
Expand
|
|
</button>
|
|
) : (
|
|
<button
|
|
type="button"
|
|
className="flex items-center gap-1 rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] px-2.5 py-1 text-[11px] text-[var(--color-text-muted)] shadow-sm transition-colors hover:bg-[var(--color-surface)] hover:text-[var(--color-text-secondary)]"
|
|
onClick={() => setExpandedAll(false)}
|
|
>
|
|
<ChevronUp size={12} />
|
|
Collapse
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|