diff --git a/src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts b/src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts new file mode 100644 index 0000000..c71d3be --- /dev/null +++ b/src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts @@ -0,0 +1,198 @@ +import { computed, type Component } from 'vue' +import type { IChatMessage } from '@/api/types' +import UserBubble from '@/components/chat/messages/UserBubble.vue' +import AssistantText from '@/components/chat/messages/AssistantText.vue' +import TeamPlanCard from '@/components/chat/messages/TeamPlanCard.vue' +import BoardBannerCard from '@/components/chat/messages/BoardBannerCard.vue' +import BoardRoundCard from '@/components/chat/messages/BoardRoundCard.vue' +import BoardConclusionCard from '@/components/chat/messages/BoardConclusionCard.vue' +import ErrorCard from '@/components/chat/messages/ErrorCard.vue' + +export type MessageViewType = + | 'user' + | 'assistant' + | 'team_plan' + | 'board_banner' + | 'board_speech' + | 'board_summary' + | 'board_conclusion' + | 'milestone' + | 'error' + +export interface MessageShellMeta { + name: string + meta?: string + avatar?: string + color?: string +} + +export interface MessageRenderSpec { + type: MessageViewType + shell: MessageShellMeta + component: Component + props: Record +} + +export function resolveMessageType(message: IChatMessage): MessageViewType { + if (message.role === 'user') return 'user' + if (message.status === 'error' || message.message_type === 'error') return 'error' + + switch (message.message_type) { + case 'plan_update': + return 'team_plan' + case 'board_started': + return 'board_banner' + case 'board_speech': + return 'board_speech' + case 'board_summary': + return 'board_summary' + case 'board_conclusion': + return 'board_conclusion' + case 'milestone': + return 'milestone' + default: + return 'assistant' + } +} + +function formatTime(timestamp: string): string { + return new Date(timestamp).toLocaleTimeString('zh-CN', { + hour: '2-digit', + minute: '2-digit', + }) +} + +export function useMessageRenderer(message: IChatMessage) { + return computed(() => { + const type = resolveMessageType(message) + const time = formatTime(message.timestamp) + + switch (type) { + case 'user': + return { + type, + shell: { name: '用户', meta: time }, + component: UserBubble, + props: { content: message.content || '' }, + } + + case 'team_plan': { + const phases = message.plan_phases ?? [] + return { + type, + shell: { + name: message.expert_name || '专家团', + meta: time, + avatar: message.expert_avatar, + color: message.expert_color, + }, + component: TeamPlanCard, + props: { + phases, + leadName: message.expert_name || 'Lead', + leadAvatar: message.expert_avatar, + leadColor: message.expert_color, + }, + } + } + + case 'board_banner': { + const data = message.board_started + const experts = data?.experts ?? [] + return { + type, + shell: { name: '私董会', meta: time }, + component: BoardBannerCard, + props: { + topic: data?.topic || message.content || '未命名主题', + experts, + maxRounds: data?.max_rounds ?? 5, + currentRound: message.board_round ?? 1, + }, + } + } + + case 'board_speech': + return { + type, + shell: { + name: message.expert_name || '专家', + meta: message.board_round ? `第 ${message.board_round} 轮${message.board_role === 'moderator' ? ' · 主持' : ''}` : time, + avatar: message.expert_avatar, + color: message.expert_color || '#a855f7', + }, + component: BoardRoundCard, + props: { + name: message.expert_name || '专家', + avatar: message.expert_avatar || '', + color: message.expert_color || '#a855f7', + round: message.board_round, + role: message.board_role === 'moderator' ? 'moderator' : 'expert', + content: message.content || '', + }, + } + + case 'board_summary': + return { + type, + shell: { + name: message.expert_name || '主持人', + meta: message.board_round ? `第 ${message.board_round} 轮 · 小结` : time, + avatar: message.expert_avatar, + color: message.expert_color || '#a855f7', + }, + component: BoardRoundCard, + props: { + name: message.expert_name || '主持人', + avatar: message.expert_avatar || '', + color: message.expert_color || '#a855f7', + round: message.board_round, + role: 'summary', + content: message.content || '', + }, + } + + case 'board_conclusion': + return { + type, + shell: { name: '主持人', meta: time }, + component: BoardConclusionCard, + props: { + data: message.board_conclusion ?? { + summary: message.content || '', + decision_advice: '', + total_rounds: message.board_round ?? 0, + consensus_points: [], + dissent_points: [], + }, + }, + } + + case 'error': + return { + type, + shell: { name: '系统', meta: time }, + component: ErrorCard, + props: { + title: '请求失败', + detail: message.error_detail || message.content || '', + }, + } + + case 'milestone': + case 'assistant': + default: + return { + type, + shell: { + name: message.expert_name || 'AI Agent', + meta: time, + avatar: message.expert_avatar, + color: message.expert_color, + }, + component: AssistantText, + props: { message }, + } + } + }) +} diff --git a/src/agentkit/server/frontend/src/components/chat/messages/TeamPlanCard.vue b/src/agentkit/server/frontend/src/components/chat/messages/TeamPlanCard.vue new file mode 100644 index 0000000..96f34b7 --- /dev/null +++ b/src/agentkit/server/frontend/src/components/chat/messages/TeamPlanCard.vue @@ -0,0 +1,271 @@ + + + + + diff --git a/src/agentkit/server/frontend/src/components/preview/scenes/Scene3TeamPlan.vue b/src/agentkit/server/frontend/src/components/preview/scenes/Scene3TeamPlan.vue new file mode 100644 index 0000000..c3a6dbb --- /dev/null +++ b/src/agentkit/server/frontend/src/components/preview/scenes/Scene3TeamPlan.vue @@ -0,0 +1,93 @@ + + + + +