agent-settings.tsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. 'use client';
  2. import { Label } from '@/components/ui/label';
  3. import { Input } from '@/components/ui/input';
  4. import { Checkbox } from '@/components/ui/checkbox';
  5. import { AlertCircle, User, Users, Sparkles, Info } from 'lucide-react';
  6. import { cn } from '@/lib/utils';
  7. import { useI18n } from '@/lib/hooks/use-i18n';
  8. import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
  9. interface Agent {
  10. id: string;
  11. name: string;
  12. avatar: string;
  13. role: string;
  14. priority: number;
  15. allowedActions: string[];
  16. }
  17. interface AgentSettingsProps {
  18. agents: Agent[];
  19. selectedAgentIds: string[];
  20. maxTurns: string;
  21. agentMode: 'preset' | 'auto';
  22. onToggleAgent: (agentId: string) => void;
  23. onMaxTurnsChange: (value: string) => void;
  24. onAgentModeChange: (mode: 'preset' | 'auto') => void;
  25. }
  26. export function AgentSettings({
  27. agents,
  28. selectedAgentIds,
  29. maxTurns,
  30. agentMode,
  31. onToggleAgent,
  32. onMaxTurnsChange,
  33. onAgentModeChange,
  34. }: AgentSettingsProps) {
  35. const { t } = useI18n();
  36. const getAgentName = (agent: Agent) => {
  37. const key = `settings.agentNames.${agent.id}`;
  38. const translated = t(key);
  39. return translated !== key ? translated : agent.name;
  40. };
  41. const getAgentRole = (agent: Agent) => {
  42. const key = `settings.agentRoles.${agent.role}`;
  43. const translated = t(key);
  44. return translated !== key ? translated : agent.role;
  45. };
  46. return (
  47. <div className="space-y-6 max-w-2xl">
  48. <div className="space-y-4">
  49. {/* Mode Toggle */}
  50. <div className="space-y-2">
  51. <Label>{t('settings.agentMode')}</Label>
  52. <div className="inline-flex rounded-lg border bg-muted/30 p-0.5">
  53. <button
  54. onClick={() => onAgentModeChange('preset')}
  55. className={cn(
  56. 'px-4 py-1.5 text-sm font-medium rounded-md transition-all',
  57. agentMode === 'preset'
  58. ? 'bg-background shadow-sm text-foreground'
  59. : 'text-muted-foreground hover:text-foreground',
  60. )}
  61. >
  62. {t('settings.agentModePreset')}
  63. </button>
  64. <button
  65. onClick={() => onAgentModeChange('auto')}
  66. className={cn(
  67. 'px-4 py-1.5 text-sm font-medium rounded-md transition-all flex items-center gap-1.5',
  68. agentMode === 'auto'
  69. ? 'bg-background shadow-sm text-foreground'
  70. : 'text-muted-foreground hover:text-foreground',
  71. )}
  72. >
  73. <Sparkles className="h-3.5 w-3.5" />
  74. {t('settings.agentModeAuto')}
  75. </button>
  76. </div>
  77. </div>
  78. {agentMode === 'preset' ? (
  79. <>
  80. {/* Preset mode: existing agent multi-select */}
  81. <div className="space-y-2">
  82. <Label>{t('settings.selectAgents')}</Label>
  83. <p className="text-sm text-muted-foreground">{t('settings.agentSettingsDesc')}</p>
  84. </div>
  85. <div className="space-y-2 border rounded-lg p-2 bg-muted/30">
  86. {agents.map((agent) => (
  87. <div
  88. key={agent.id}
  89. className={cn(
  90. 'flex items-center space-x-3 p-3 rounded-lg border transition-all cursor-pointer',
  91. selectedAgentIds.includes(agent.id)
  92. ? 'bg-primary/10 border-primary/50 shadow-sm'
  93. : 'bg-background hover:bg-muted/50 border-transparent',
  94. )}
  95. onClick={() => onToggleAgent(agent.id)}
  96. >
  97. <Checkbox
  98. id={`agent-${agent.id}`}
  99. checked={selectedAgentIds.includes(agent.id)}
  100. onCheckedChange={() => onToggleAgent(agent.id)}
  101. disabled={agent.role === 'teacher'}
  102. />
  103. <Avatar className="size-10">
  104. <AvatarImage src={agent.avatar} alt={getAgentName(agent)} />
  105. <AvatarFallback>{getAgentName(agent).charAt(0)}</AvatarFallback>
  106. </Avatar>
  107. <div className="flex-1">
  108. <div className="font-medium text-sm flex items-center gap-1.5">
  109. {getAgentName(agent)}
  110. {agent.role === 'teacher' && (
  111. <span className="text-[10px] px-1.5 py-0.5 rounded bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 leading-none">
  112. {t('settings.required')}
  113. </span>
  114. )}
  115. </div>
  116. <div className="text-xs text-muted-foreground">{getAgentRole(agent)}</div>
  117. </div>
  118. </div>
  119. ))}
  120. </div>
  121. {/* Mode indicator */}
  122. <div
  123. className={`p-3 rounded-lg text-sm ${
  124. selectedAgentIds.length === 0
  125. ? 'bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-300 border border-red-200 dark:border-red-800'
  126. : selectedAgentIds.length === 1
  127. ? 'bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 border border-blue-200 dark:border-blue-800'
  128. : 'bg-purple-50 dark:bg-purple-900/20 text-purple-700 dark:text-purple-300 border border-purple-200 dark:border-purple-800'
  129. }`}
  130. >
  131. {selectedAgentIds.length === 0 && (
  132. <span className="flex items-center gap-1.5">
  133. <AlertCircle className="h-4 w-4" />
  134. {t('settings.atLeastOneAgent')}
  135. </span>
  136. )}
  137. {selectedAgentIds.length === 1 && (
  138. <span className="flex items-center gap-1.5">
  139. <User className="h-4 w-4" />
  140. <strong>{t('settings.singleAgentMode')}</strong> -{' '}
  141. {(() => {
  142. const agent = agents.find((a) => a.id === selectedAgentIds[0]);
  143. return agent ? getAgentName(agent) : t('settings.selectedAgent');
  144. })()}{' '}
  145. {t('settings.directAnswer')}
  146. </span>
  147. )}
  148. {selectedAgentIds.length > 1 && (
  149. <span className="flex items-center gap-1.5">
  150. <Users className="h-4 w-4" />
  151. <strong>{t('settings.multiAgentMode')}</strong> -{' '}
  152. {t('settings.agentsCollaboratingCount', {
  153. count: selectedAgentIds.length,
  154. })}
  155. </span>
  156. )}
  157. </div>
  158. {/* Max turns config - only show for multi-agent */}
  159. {selectedAgentIds.length > 1 && (
  160. <div className="space-y-2 border-l-4 border-purple-500 pl-4">
  161. <Label>{t('settings.maxTurns')}</Label>
  162. <p className="text-xs text-muted-foreground">{t('settings.maxTurnsDesc')}</p>
  163. <Input
  164. type="number"
  165. min="1"
  166. max="20"
  167. value={maxTurns}
  168. onChange={(e) => onMaxTurnsChange(e.target.value)}
  169. className="w-24"
  170. />
  171. </div>
  172. )}
  173. </>
  174. ) : (
  175. <>
  176. {/* Auto mode: description */}
  177. <div className="flex items-start gap-2.5 p-3 rounded-lg bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-300 border border-green-200 dark:border-green-800 text-sm">
  178. <Info className="h-4 w-4 mt-0.5 shrink-0" />
  179. <span>{t('settings.agentModeAutoDesc')}</span>
  180. </div>
  181. </>
  182. )}
  183. </div>
  184. </div>
  185. );
  186. }