agent-config-panel.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /**
  2. * Agent Configuration Panel
  3. * UI for viewing and managing AI agents in the registry
  4. */
  5. 'use client';
  6. import { useState } from 'react';
  7. import { useAgentRegistry } from '@/lib/orchestration/registry/store';
  8. import { Button } from '@/components/ui/button';
  9. import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
  10. import { Badge } from '@/components/ui/badge';
  11. import { ScrollArea } from '@/components/ui/scroll-area';
  12. import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
  13. import { PlusIcon, Trash2Icon, EditIcon } from 'lucide-react';
  14. export function AgentConfigPanel() {
  15. const { listAgents, deleteAgent } = useAgentRegistry();
  16. const agents = listAgents();
  17. const [selectedAgent, setSelectedAgent] = useState<string | null>(null);
  18. const handleDelete = (agentId: string) => {
  19. if (confirm('确定要删除这个智能体吗?')) {
  20. deleteAgent(agentId);
  21. if (selectedAgent === agentId) {
  22. setSelectedAgent(null);
  23. }
  24. }
  25. };
  26. return (
  27. <div className="flex flex-col h-full p-4 gap-4">
  28. <div className="flex items-center justify-between">
  29. <div>
  30. <h2 className="text-lg font-semibold">智能体配置</h2>
  31. <p className="text-sm text-muted-foreground">管理课堂讨论的AI智能体</p>
  32. </div>
  33. <Button size="sm" variant="outline">
  34. <PlusIcon className="w-4 h-4 mr-2" />
  35. 新建
  36. </Button>
  37. </div>
  38. <ScrollArea className="flex-1">
  39. <div className="space-y-3">
  40. {agents.map((agent) => (
  41. <Card
  42. key={agent.id}
  43. className={`cursor-pointer transition-colors ${
  44. selectedAgent === agent.id ? 'border-primary' : ''
  45. }`}
  46. onClick={() => setSelectedAgent(agent.id)}
  47. >
  48. <CardHeader className="p-4">
  49. <div className="flex items-start justify-between">
  50. <div className="flex items-center gap-3">
  51. <Avatar
  52. className="size-10"
  53. style={{
  54. borderColor: agent.color,
  55. borderWidth: 2,
  56. }}
  57. >
  58. <AvatarImage src={agent.avatar} alt={agent.name} />
  59. <AvatarFallback
  60. style={{
  61. backgroundColor: `${agent.color}20`,
  62. color: agent.color,
  63. }}
  64. >
  65. {agent.name.charAt(0)}
  66. </AvatarFallback>
  67. </Avatar>
  68. <div>
  69. <CardTitle className="text-base">{agent.name}</CardTitle>
  70. <CardDescription className="text-sm">{agent.role}</CardDescription>
  71. </div>
  72. </div>
  73. <div className="flex gap-2">
  74. <Badge variant="secondary" className="text-xs">
  75. 优先级 {agent.priority}
  76. </Badge>
  77. {agent.isDefault && (
  78. <Badge variant="outline" className="text-xs">
  79. 默认
  80. </Badge>
  81. )}
  82. </div>
  83. </div>
  84. </CardHeader>
  85. <CardContent className="p-4 pt-0">
  86. <div className="space-y-2">
  87. <div>
  88. <p className="text-xs font-medium text-muted-foreground mb-1">能力描述</p>
  89. <p className="text-sm line-clamp-2">{agent.persona}</p>
  90. </div>
  91. <div>
  92. <p className="text-xs font-medium text-muted-foreground mb-1">
  93. 可用动作 ({agent.allowedActions.length})
  94. </p>
  95. <div className="flex flex-wrap gap-1">
  96. {agent.allowedActions.slice(0, 3).map((tool) => (
  97. <Badge key={tool} variant="secondary" className="text-xs">
  98. {tool}
  99. </Badge>
  100. ))}
  101. {agent.allowedActions.length > 3 && (
  102. <Badge variant="secondary" className="text-xs">
  103. +{agent.allowedActions.length - 3}
  104. </Badge>
  105. )}
  106. </div>
  107. </div>
  108. {!agent.isDefault && (
  109. <div className="flex gap-2 pt-2">
  110. <Button size="sm" variant="outline" className="flex-1">
  111. <EditIcon className="w-3 h-3 mr-1" />
  112. 编辑
  113. </Button>
  114. <Button
  115. size="sm"
  116. variant="destructive"
  117. onClick={(e) => {
  118. e.stopPropagation();
  119. handleDelete(agent.id);
  120. }}
  121. >
  122. <Trash2Icon className="w-3 h-3" />
  123. </Button>
  124. </div>
  125. )}
  126. </div>
  127. </CardContent>
  128. </Card>
  129. ))}
  130. </div>
  131. </ScrollArea>
  132. {agents.length === 0 && (
  133. <div className="flex-1 flex items-center justify-center text-center p-8">
  134. <div className="max-w-sm">
  135. <p className="text-muted-foreground mb-4">还没有配置智能体</p>
  136. <Button>
  137. <PlusIcon className="w-4 h-4 mr-2" />
  138. 创建第一个智能体
  139. </Button>
  140. </div>
  141. </div>
  142. )}
  143. </div>
  144. );
  145. }