🦸 飞行侠完善:Agent 信箱 + 回复功能 + 完整测试

功能增强:
- meetings/views.py: inbox 接口支持 Agent 自动加入会议
- meetings/views.py: 新增 agent_reply 接口供 Agent 回复消息
- meeting_agent.py: 更新回复接口调用
- test_full.py: 新增完整功能测试脚本(7 项测试)
- README.md: 编写详细使用指南

测试结果:
 用户登录
 创建会议
 获取会议列表
 发送消息
 获取消息
 Agent 信箱(自动加入)
 Agent 回复
This commit is contained in:
2026-04-04 11:28:24 +08:00
parent c9f41b6410
commit 7697d26682
4 changed files with 455 additions and 16 deletions

View File

@@ -176,9 +176,11 @@ class MeetingViewSet(viewsets.ModelViewSet):
@action(detail=True, methods=['get'])
def inbox(self, request, pk=None):
"""Agent 查阅信箱"""
"""Agent 查阅信箱(自动加入会议如果还没加入)"""
meeting = self.get_object()
agent_id = request.query_params.get('agent_id')
agent_name = request.query_params.get('agent_name', 'Agent')
agent_emoji = request.query_params.get('agent_emoji', '🤖')
if not agent_id:
return Response(
@@ -186,13 +188,23 @@ class MeetingViewSet(viewsets.ModelViewSet):
status=status.HTTP_400_BAD_REQUEST
)
# 找到这个 Agent 的参会记录
participant = get_object_or_404(
Participant,
# 找到或创建这个 Agent 的参会记录
participant = Participant.objects.filter(
meeting=meeting,
agent_id=agent_id,
left_at__isnull=True
)
).first()
if not participant:
# Agent 首次访问,自动加入会议
participant = Participant.objects.create(
meeting=meeting,
agent_type='openclaw',
agent_id=agent_id,
agent_name=agent_name,
agent_emoji=agent_emoji,
nickname=f"{agent_emoji} {agent_name}"
)
# 获取发给这个 Agent 的消息(未读)
messages = Message.objects.filter(
@@ -201,16 +213,67 @@ class MeetingViewSet(viewsets.ModelViewSet):
read_by=participant
)
# 如果是群发消息,所有人都能看到
# 如果是指定消息,需要检查 recipients
# 简化版:所有未读消息都返回
# 标记为已读
participant.read_messages.add(*messages)
serializer = MessageSerializer(messages, many=True)
return Response({
'unread_count': messages.count(),
'messages': serializer.data
'messages': serializer.data,
'participant': ParticipantSerializer(participant).data
})
@action(detail=True, methods=['post'])
def agent_reply(self, request, pk=None):
"""Agent 回复消息"""
meeting = self.get_object()
agent_id = request.data.get('agent_id')
agent_name = request.data.get('agent_name', 'Agent')
agent_emoji = request.data.get('agent_emoji', '🤖')
content = request.data.get('content')
in_reply_to = request.data.get('in_reply_to')
if not agent_id:
return Response(
{'error': '缺少 agent_id 参数'},
status=status.HTTP_400_BAD_REQUEST
)
if not content:
return Response(
{'error': '消息内容不能为空'},
status=status.HTTP_400_BAD_REQUEST
)
# 找到或创建 Agent 参会记录
participant = Participant.objects.filter(
meeting=meeting,
agent_id=agent_id,
left_at__isnull=True
).first()
if not participant:
participant = Participant.objects.create(
meeting=meeting,
agent_type='openclaw',
agent_id=agent_id,
agent_name=agent_name,
agent_emoji=agent_emoji,
nickname=f"{agent_emoji} {agent_name}"
)
# 创建回复消息
message = Message.objects.create(
meeting=meeting,
sender=participant,
content=content,
is_broadcast=request.data.get('is_broadcast', True),
requires_response=request.data.get('requires_response', False),
in_reply_to_id=in_reply_to
)
return Response(MessageSerializer(message).data, status=status.HTTP_201_CREATED)
class ParticipantViewSet(viewsets.ModelViewSet):