feat(aia): Complete AIA V2.0 with universal streaming capabilities

Major Updates:
- Add StreamingService with OpenAI Compatible format (backend/common/streaming)
- Upgrade Chat component V2 with Ant Design X integration
- Implement AIA module with 12 intelligent agents
- Create AgentHub with 100% prototype V11 restoration
- Create ChatWorkspace with streaming response support
- Add ThinkingBlock for deep thinking display
- Add useAIStream Hook for OpenAI Compatible stream handling

Backend Common Capabilities (~400 lines):
- OpenAIStreamAdapter: SSE adapter with OpenAI format
- StreamingService: unified streaming service
- Support content and reasoning_content dual streams
- Deep thinking tag processing (<think>...</think>)

Frontend Common Capabilities (~2000 lines):
- AIStreamChat: modern streaming chat component
- ThinkingBlock: collapsible deep thinking display
- ConversationList: conversation management with grouping
- useAIStream: OpenAI Compatible stream handler Hook
- useConversations: conversation state management Hook
- Modern design styles (Ultramodern theme)

AIA Module Frontend (~1500 lines):
- AgentHub: 12 agent cards with timeline design
- ChatWorkspace: fullscreen immersive chat interface
- AgentCard: theme-colored cards (blue/yellow/teal/purple)
- 5 phases, 12 agents configuration
- Responsive layout (desktop + mobile)

AIA Module Backend (~900 lines):
- agentService: 12 agents config with system prompts
- conversationService: refactored with StreamingService
- attachmentService: file upload skeleton (30k token limit)
- 12 API endpoints with authentication
- Full CRUD for conversations and messages

Documentation:
- AIA module status and development guide
- Universal capabilities catalog (11 services)
- Quick reference card for developers
- System overview updates

Testing:
- Stream response verified (HTTP 200)
- Authentication working correctly
- Auto conversation creation working
- Deep thinking display working
- Message input and send working

Status: Core features completed (85%), attachment and history loading pending
This commit is contained in:
2026-01-14 19:09:28 +08:00
parent 4ed67a8846
commit 3d35e9c58b
38 changed files with 8448 additions and 335 deletions

View File

@@ -0,0 +1,169 @@
/**
* ConversationList - 会话列表组件
*
* 现代感设计的会话列表,支持:
* - 分组显示(今天、昨天、更早)
* - 新建会话
* - 会话切换
* - 会话删除
* - 智能体图标
*/
import React, { useMemo } from 'react';
import { Button, Typography, Dropdown, Empty } from 'antd';
import {
PlusOutlined,
MessageOutlined,
DeleteOutlined,
MoreOutlined,
RobotOutlined,
} from '@ant-design/icons';
import type { Conversation, ConversationGroup } from './hooks/useConversations';
import './styles/conversation-list.css';
const { Text } = Typography;
/**
* ConversationList Props
*/
export interface ConversationListProps {
/** 分组会话列表 */
groups: ConversationGroup[];
/** 当前会话 ID */
currentId: string | null;
/** 会话点击回调 */
onSelect: (id: string) => void;
/** 新建会话回调 */
onNew: () => void;
/** 删除会话回调 */
onDelete?: (id: string) => void;
/** 标题 */
title?: string;
/** Logo */
logo?: React.ReactNode;
/** 自定义类名 */
className?: string;
/** 是否加载中 */
loading?: boolean;
}
/**
* 会话列表组件
*/
export const ConversationList: React.FC<ConversationListProps> = ({
groups,
currentId,
onSelect,
onNew,
onDelete,
title = 'AI 助手',
logo,
className = '',
loading = false,
}) => {
// 会话项菜单
const getMenuItems = (conv: Conversation) => [
{
key: 'delete',
icon: <DeleteOutlined />,
label: '删除对话',
danger: true,
onClick: () => onDelete?.(conv.id),
},
];
// 是否为空
const isEmpty = useMemo(() => {
return groups.every(g => g.conversations.length === 0);
}, [groups]);
return (
<div className={`conversation-list ${className}`}>
{/* 头部 */}
<div className="conversation-list-header">
<div className="conversation-list-logo">
{logo || <RobotOutlined className="default-logo" />}
<span className="conversation-list-title">{title}</span>
</div>
</div>
{/* 新建会话按钮 */}
<div className="conversation-list-new">
<Button
type="default"
icon={<PlusOutlined />}
onClick={onNew}
block
className="new-conversation-btn"
>
</Button>
</div>
{/* 会话列表 */}
<div className="conversation-list-content">
{isEmpty ? (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="暂无对话"
className="conversation-empty"
/>
) : (
groups.map(group => (
<div key={group.key} className="conversation-group">
<div className="conversation-group-label">
<Text type="secondary">{group.label}</Text>
</div>
{group.conversations.map(conv => (
<div
key={conv.id}
className={`conversation-item ${currentId === conv.id ? 'active' : ''}`}
onClick={() => onSelect(conv.id)}
>
<div className="conversation-item-icon">
{conv.agentIcon ? (
<span className="agent-icon">{conv.agentIcon}</span>
) : (
<MessageOutlined />
)}
</div>
<div className="conversation-item-content">
<div className="conversation-item-title">
{conv.title || '新对话'}
</div>
{conv.lastMessage && (
<div className="conversation-item-preview">
{conv.lastMessage}
</div>
)}
</div>
{onDelete && (
<Dropdown
menu={{ items: getMenuItems(conv) }}
trigger={['click']}
placement="bottomRight"
>
<Button
type="text"
size="small"
icon={<MoreOutlined />}
className="conversation-item-more"
onClick={(e) => e.stopPropagation()}
/>
</Dropdown>
)}
</div>
))}
</div>
))
)}
</div>
</div>
);
};
export default ConversationList;