feat(consultation): unify server-distributed agents without fixed roles

This commit is contained in:
brother7 committed 2026-09-24 11:56:42 +08:00
1 parent 248776d855
commit 8a157be4f6
35 files changed
+625 -668

No files matched your search

+14 -13
View File
@@ -1,6 +1,6 @@
import { ArrowUpRight, Loader2, X } from 'lucide-react';
import type { Ref } from 'react';
import teacherAvatar from '@/assets/consultations/teacher-pixel.png';
import { getAgentAvatarSrc } from '@/lib/agent-avatars';
import type { useTeacherCompanion } from './use-teacher-companion';
type Companion = ReturnType<typeof useTeacherCompanion>;
@@ -11,32 +11,33 @@ export function TeacherCompanion({ companion, open, onOpen, bubbleRef }: {
bubbleRef?: Ref<HTMLDivElement>;
}) {
const { definition, invitation, welcome, loading, enabled, checking, error } = companion;
const name = definition?.name || '老师';
const name = definition?.name || '智能体';
const avatar = getAgentAvatarSrc(definition?.avatar_id);
const viewConversation = () => { companion.dismiss(); onOpen(); };
const status = loading ? '正在连接老师…'
: checking ? '老师在看看你最近的进展…'
: error || (!enabled ? '老师暂未开放,仍可查看以往讨论' : open ? '我们慢慢聊,想到什么都可以说' : '点我聊聊,想到什么都可以说');
const status = loading ? '正在连接智能体…'
: checking ? '智能体在看看你最近的进展…'
: error || (!enabled ? '智能体暂未开放,仍可查看以往讨论' : open ? '我们慢慢聊,想到什么都可以说' : '点我聊聊,想到什么都可以说');
return (
<section className="teacher-companion no-drag" aria-label="老师陪伴" data-testid="teacher-companion">
<button type="button" className="teacher-companion-person" title={status} aria-label="老师" aria-expanded={open} aria-controls="coding-consultation-dock" onMouseDown={(event) => event.preventDefault()} onClick={onOpen}>
<span className="teacher-companion-avatar"><img src={teacherAvatar} alt="" />{invitation && <span className="teacher-companion-unread" aria-hidden="true" />}</span>
<section className="teacher-companion no-drag" aria-label="智能体陪伴" data-testid="teacher-companion">
<button type="button" className="teacher-companion-person" title={status} aria-label="智能体" aria-expanded={open} aria-controls="coding-consultation-dock" onMouseDown={(event) => event.preventDefault()} onClick={onOpen}>
<span className="teacher-companion-avatar"><img src={avatar} alt="" />{invitation && <span className="teacher-companion-unread" aria-hidden="true" />}</span>
<span className="teacher-companion-name">{name}</span>
{checking && <Loader2 className="h-3 w-3 shrink-0 animate-spin text-muted-foreground motion-reduce:animate-none" aria-label="老师正在思考" />}
{checking && <Loader2 className="h-3 w-3 shrink-0 animate-spin text-muted-foreground motion-reduce:animate-none" aria-label="智能体正在思考" />}
</button>
{(invitation || welcome) && <div ref={bubbleRef} className="teacher-companion-presence" data-testid="teacher-presence">
<div className="teacher-companion-bubble" data-testid="teacher-invitation" data-bubble-kind={invitation ? 'check-in' : 'welcome'}>
<div className="teacher-companion-bubble-heading">
<div className="teacher-companion-invitation-label">{name}</div>
<button type="button" className="teacher-companion-dismiss" aria-label="收起老师气泡" onClick={companion.dismiss}><X className="h-3.5 w-3.5" aria-hidden="true" /></button>
<button type="button" className="teacher-companion-dismiss" aria-label="收起智能体气泡" onClick={companion.dismiss}><X className="h-3.5 w-3.5" aria-hidden="true" /></button>
</div>
<p className="teacher-companion-message" role="status">{invitation?.response ?? welcome}</p>
<div className="teacher-companion-actions">
<button type="button" onClick={viewConversation}>{open ? '看看老师说的' : '和老师聊聊'} <ArrowUpRight aria-hidden="true" className="h-3 w-3" /></button>
<button type="button" onClick={viewConversation}>{open ? '看看智能体说的' : '和智能体聊聊'} <ArrowUpRight aria-hidden="true" className="h-3 w-3" /></button>
<button type="button" onClick={companion.dismiss}>等会儿聊</button>
</div>
</div>
<button type="button" className="teacher-companion-speaker" aria-label="打开这条老师消息" onMouseDown={(event) => event.preventDefault()} onClick={viewConversation}>
<img src={teacherAvatar} alt="" />
<button type="button" className="teacher-companion-speaker" aria-label="打开这条智能体消息" onMouseDown={(event) => event.preventDefault()} onClick={viewConversation}>
<img src={avatar} alt="" />
</button>
</div>}
</section>