Planning Phase 14 - huqianghui/AI-Coach-vibe-coding GitHub Wiki
Auto-generated from
.planning/phases/14-hcp-agent-refactor-vl-instance-read-only-reference-knowledge-tools-config
Last synced: 2026-04-28
Gathered: 2026-04-06 Status: Ready for planning Source: Conversation context + plan mode plan + infrastructure audit
## Phase Boundary重构 HCP 编辑器对齐 AI Foundry Agent 页面设计:
- Voice Live 配置从 HCP 编辑器移至只读引用(来自 VL Instance)
- VL Management 页成为语音/数字人配置的唯一编辑入口
- HCP 编辑器聚焦 Agent 属性(Instructions/Prompt、Knowledge、Tools)
- Avatar 缩略图使用 Azure CDN 真人图片(已在 Phase 13 实现)
关键前提:VL Instance 后端基础设施已完全构建(Model, Schema, Service, API, Migration, Frontend hooks 全部就绪)。Phase 14 主要是前端重构。
## Implementation Decisions- VL Management 页改为 VL Instance CRUD 管理页(不再是 HCP 卡片仪表盘)
- 每个实例卡片显示: 名称, 模型, 语音, 数字人角色缩略图, 引用 HCP 数
- 创建/编辑 Dialog 包含完整配置表单:模型选择、语音设置、数字人选择、对话参数、Agent 指令覆盖
- Avatar 选择器复用 voice-avatar-tab.tsx 的 Standard/Custom tabs + Photo/Video filter
- 实例可以分配给多个 HCP(一对多关系)
- 删除有 HCP 引用的实例 → 409 Conflict
- 从 950 行完整配置编辑器 → 简化为只读预览 + VL Instance 下拉选择器
- 下拉选择器显示实例名称 + 模型 + 数字人角色缩略图
- 只读展示选中实例的关键配置(不可在 HCP 中编辑 VL 配置)
- "新建配置" 按钮跳转到 VL Management 页
- 保留实时测试面板(使用选中实例的配置)
- 需要新增
POST /voice-live/instances/unassign端点(从 HCP 取消 VL 关联) - 现有 assign 端点:
POST /voice-live/instances/{id}/assign
- HCP-14-04 已在 Phase 13 的 voice-avatar-tab 改进中基本完成(使用 CDN 真人图片替代字母圆圈)
- VL Management 实例卡片也需要显示数字人缩略图
- VL Instance 创建/编辑 Dialog 的具体布局和分区
- Knowledge/Tools 区域的具体 UI 组件(Phase 14 scope 可能推迟到后续)
- 实时测试面板的复用策略
<canonical_refs>
Downstream agents MUST read these before planning or implementing.
-
backend/app/models/voice_live_instance.py— ORM model with all 15 voice config fields -
backend/app/schemas/voice_live_instance.py— 5 Pydantic schemas (Create, Update, Response, Summary, List, Assign) -
backend/app/services/voice_live_instance_service.py— Full CRUD + assign + resolve_voice_config -
backend/app/api/voice_live.py— 6 instance endpoints (POST/GET/PUT/DELETE + list + assign) -
backend/alembic/versions/m16a_create_voice_live_instances.py— Migration creating table + FK + data migration
-
backend/app/services/voice_live_service.py— Token broker with resolve_voice_config -
backend/app/services/voice_live_websocket.py— WebSocket config loading -
backend/app/models/hcp_profile.py— HcpProfile with voice_live_instance_id FK
-
frontend/src/hooks/use-voice-live-instances.ts— TanStack Query hooks for all CRUD -
frontend/src/pages/admin/voice-live-management.tsx— Basic management page (needs major rework) -
frontend/src/components/admin/voice-live-chain-card.tsx— Instance display card (needs rework) -
frontend/src/types/voice-live.ts— TypeScript types for VL Instance
-
frontend/src/components/admin/voice-avatar-tab.tsx— 完整 avatar 选择器(Standard/Custom tabs, Photo/Video filter, CDN 缩略图)
frontend/public/locales/en-US/admin.jsonfrontend/public/locales/zh-CN/admin.json
</canonical_refs>
## Specific Ideas- VL Management 页面参考 AI Foundry Voice Live Playground — admin 定义 voice live 实例,配置模型、avatar/voice、对话参数,然后 assign 给 HCP
- Avatar 选择器从 voice-avatar-tab.tsx 提取 — 当前在 HCP 编辑器中的 avatar 选择器需要提取为独立组件,在 VL Management 和 HCP Voice Tab 中复用
- 实例卡片显示数字人缩略图 — 使用 CDN URL,不是字母圆圈
- 配置解析优先级: VoiceLiveInstance → HcpProfile 旧字段(回退兼容)
- Knowledge 区域(HCP-14-02)— 添加/移除知识库功能可能推迟到后续 phase
- Tools 区域(HCP-14-03)— Function Call 配置可能推迟到后续 phase
- 上述两项的后端 API 和模型尚未设计
Phase: 14-hcp-agent-refactor-vl-instance-read-only-reference-knowledge-tools-config Context gathered: 2026-04-06 via conversation context + plan mode
| # | Plan File | Status |
|---|---|---|
| 14-01 | 14-01-PLAN.md | Complete |
| 14-02 | 14-02-PLAN.md | Complete |
| 14-03 | 14-03-PLAN.md | Complete |
| 14-04 | 14-04-PLAN.md | Pending |
Click to expand UI spec
Visual and interaction contract for the HCP Agent Refactor phase. Generated by gsd-ui-researcher, verified by gsd-ui-checker.
| Property | Value |
|---|---|
| Tool | Manual Radix UI wrappers (shadcn-style, initialized Phase 01) |
| Preset | Custom Figma Make SaaS theme (Phase 01-02) |
| Component library | Radix UI (Dialog, Select, Tabs, Switch, Slider, etc.) |
| Icon library | lucide-react ^0.460.0 |
| Font | Inter + Noto Sans SC (sans-serif), JetBrains Mono (monospace) |
Reused from existing library (no new UI primitives needed):
-
Dialog,DialogContent,DialogHeader,DialogTitle,DialogDescription,DialogFooter -
Select,SelectContent,SelectItem,SelectTrigger,SelectValue,SelectGroup,SelectLabel -
Card,CardHeader,CardContent,CardFooter,CardTitle -
Button,Badge,Input,Label,Textarea,Switch,Slider -
Tabs,TabsList,TabsTrigger,TabsContent -
Skeleton,ScrollArea - Shared:
EmptyState
Declared values (must be multiples of 4):
| Token | Value | Usage |
|---|---|---|
| xs | 4px | Icon gaps (size-1), inline padding (p-1) |
| sm | 8px | Compact element spacing (gap-2, p-2), avatar grid gaps |
| md | 16px | Default element spacing (gap-4, p-4, space-y-4) |
| lg | 24px | Section padding (space-y-6, gap-6), card grid gaps |
| xl | 32px | Layout gaps (space-y-8), page header to content |
| 2xl | 48px | Page-level vertical rhythm (py-12 in empty states) |
| 3xl | 64px | Not used in this phase |
Exceptions: Avatar grid items use gap-2 (8px) for tight thumbnail layout. Dialog max-height uses max-h-[90vh] viewport-relative.
| Role | Size | Weight | Line Height | Usage in Phase 14 |
|---|---|---|---|---|
| Body | 14px (text-sm) | 400 (normal) | 1.5 | Card content rows, config preview values, dialog descriptions |
| Label | 14px (text-sm) | 600 (semibold) | 1.5 | Section headings (h4), form labels, card titles |
| Heading | 24px (text-2xl) | 600 (semibold) | 1.5 | Page title ("Voice Live Management") |
| Micro | 10px (text-[10px]) | 400 (normal) | 1.3 | Avatar name labels in grid, hint text below selectors |
Note: Phase 14 uses only 2 weights (400 + 600) consistent with project convention (--font-weight-normal: 400, --font-weight-medium: 500 used as 600 semibold in headings).
| Role | Value | Usage |
|---|---|---|
| Dominant (60%) |
var(--background) / #FFFFFF |
Page background, dialog background |
| Secondary (30%) |
var(--card) / #FFFFFF with border |
Instance cards, config preview cards, form sections |
| Accent (10%) |
var(--primary) / #1E40AF |
Selected avatar ring, primary CTA buttons, link text |
| Destructive |
var(--destructive) / #EF4444 |
Delete buttons, unassign confirmation, remove icon hover |
| Muted surface |
var(--muted) / #F9FAFB |
Empty state background, avatar placeholder bg, skeleton loading |
| Muted text |
var(--muted-foreground) / #6B7280 |
Secondary labels, descriptions, icon tints, disabled text |
Accent reserved for:
- "Save" / "New Instance" primary CTA buttons
- Avatar selection ring (
ring-2 ring-primary border-primary) - Enabled badge (
variant="default") - "Manage in Voice Live" link text
- Instance selector dropdown active state
File: frontend/src/pages/admin/voice-live-management.tsx
Layout: space-y-8 vertical stack
- Page header: title (text-2xl) + description (text-sm muted) + "New Instance" button
- Summary stat cards: 3-column grid (
grid-cols-2 md:grid-cols-3 gap-4) - Instance cards grid:
grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6 - Delete confirmation Dialog
- Assign-to-HCP Dialog
States:
- Loading: 6x Skeleton cards (
h-56 rounded-lg) - Error: muted bg + error text + Retry button
- Empty: EmptyState component with i18n copy
- Populated: Instance card grid
File: frontend/src/components/admin/voice-live-chain-card.tsx
Layout: Card with CardHeader + CardContent + CardFooter
- Header: Avatar thumbnail (w-12, aspect-[3/4]) + name + enabled/disabled Badge
- Content: Model row, voice row (Mic icon), avatar row, HCP count (expandable)
- Footer: Edit (ghost), Assign (ghost), Delete (ghost destructive)
- Expanded: assigned HCP list with unassign X buttons, border-l-2 indent
Avatar thumbnail contract:
- Container:
w-12 aspect-[3/4] overflow-hidden rounded-lg bg-muted/30 - CDN source:
https://learn.microsoft.com/en-us/azure/ai-services/speech-service/text-to-speech-avatar/media/{character}-{style}.png - Fallback: gradient circle with initials (2-char) from
getAvatarInitials() - Error handling:
onErrorsets ref flag, re-renders to show fallback
File: frontend/src/components/admin/vl-instance-dialog.tsx
Layout: Dialog (sm:max-w-2xl max-h-[90vh] overflow-y-auto)
- 6 sections separated by
space-y-6:- Identity: Name input + Description textarea + Enabled switch
- Model:
VoiceLiveModelSelect(tiered: Pro/Standard/Lite) - Voice: Voice name select + Temperature slider (0-2, step 0.1)
- Avatar: Filter tabs (All/Photo/Video) + scrollable grid (
grid-cols-4 gap-2 max-h-60) - Conversation: Turn detection + language (2-col grid) + 3 switches (noise/echo/EOU)
- Agent Instructions: Override textarea (3 rows)
- Footer: Cancel (outline) + Save (primary, disabled when saving or name empty)
Avatar grid item contract:
- Container:
flex-col items-center gap-1 rounded-lg border p-2 - Selected state:
ring-2 ring-primary border-primary - Thumbnail:
h-14 w-14 rounded-full object-cover - Label:
text-[10px] leading-tight text-center truncate w-full
File: frontend/src/components/admin/voice-avatar-tab.tsx
Layout: space-y-4 max-w-2xl
- Section 1 — Instance Selector Card:
- Select dropdown with instances (name + model badge)
- X button to remove assignment
- "Manage in Voice Live" link (ExternalLink icon)
- New profile hint text (text-[10px])
- Section 2 — Config Preview Card (when instance assigned):
- CardTitle: "Configuration Preview" (text-sm semibold)
- 2-column grid (
grid-cols-2 gap-x-6 gap-y-3) with ConfigRow components - Rows: Model (Badge), Voice (Volume2 icon), Avatar (thumbnail + name), Temperature, Turn Detection, Language
- Footer: Enabled/Disabled badge + HCP count
- Section 3 — No Instance Empty State (when no instance):
-
bg-muted/50 rounded-lg p-6centered layout - Monitor icon (size-10 muted)
- Title + description + "Manage in Voice Live" outline button
-
ConfigRow contract:
- Label:
text-xs text-muted-foreground - Value: child content in
div
AvatarThumbnail contract (inline):
- Container:
w-8 aspect-[3/4] overflow-hidden rounded-md bg-muted/30 - Fallback: gradient initials circle
Location: Inside HCP editor Tabs Layout: EmptyState-like centered layout
- BookOpen icon (lucide-react)
- Title: i18n
voiceLive.knowledgePlaceholderTitle("Knowledge Base") - Body: i18n
voiceLive.knowledgePlaceholderBody(future update notice)
Location: Inside HCP editor Tabs Layout: EmptyState-like centered layout
- Wrench icon (lucide-react)
- Title: i18n
voiceLive.toolsPlaceholderTitle("Function Call Tools") - Body: i18n
voiceLive.toolsPlaceholderBody(future update notice)
File: frontend/src/pages/admin/hcp-profile-editor.tsx
Tabs: 4 tabs (expanded from 2 in Phase 12):
- Profile (existing)
- Voice & Avatar (simplified to read-only)
- Knowledge (new placeholder)
- Tools (new placeholder)
Tab icons: Save, Volume2/Monitor, BookOpen, Wrench (from lucide-react)
| Element | en-US Copy | zh-CN Copy |
|---|---|---|
| VL Management page title | "Voice Live Management" | "Voice Live 管理" |
| VL Management description | "Manage reusable Voice Live configuration instances. Create instances and assign them to HCP profiles." | "管理可复用的 Voice Live 配置实例。创建实例并分配给 HCP 档案。" |
| Primary CTA (VL page) | "New Instance" | "新建实例" |
| Primary CTA (dialog) | "Save" | "保存" |
| Empty state heading (VL) | "No Voice Live Instances" | "暂无 Voice Live 实例" |
| Empty state body (VL) | "Create your first Voice Live configuration instance to get started." | "创建您的第一个 Voice Live 配置实例以开始使用。" |
| Error state (VL load) | "Failed to load Voice Live instances. Click retry to try again." | "加载 Voice Live 实例失败。点击重试再试一次。" |
| Delete confirmation | "Are you sure you want to delete "{{name}}"?" | "确定要删除 "{{name}}" 吗?" |
| Delete conflict | "Cannot delete: {{count}} HCP profile(s) still reference this instance." | "无法删除:仍有 {{count}} 个 HCP 档案引用此实例。" |
| Assign dialog title | "Assign Instance to HCP" | "将实例分配给 HCP" |
| Remove confirm (HCP tab) | "Remove Voice Live Instance "{{name}}" from this HCP? The HCP will fall back to inline settings." | "从此 HCP 移除 Voice Live 实例 "{{name}}"?HCP 将回退到内联设置。" |
| No instance (HCP tab) | "No Voice Live Instance assigned" | "未分配 Voice Live 实例" |
| Read-only hint | "Voice/avatar settings come from the assigned Voice Live Instance. Edit in Voice Live Management." | "语音/数字人设置来自分配的 Voice Live 实例。在 Voice Live 管理页面编辑。" |
| Knowledge placeholder | "Knowledge base configuration (product materials, clinical references) will be available in a future update." | "知识库配置(产品资料、临床参考)将在未来版本中提供。" |
| Tools placeholder | "Function Call tool configuration will be available in a future update." | "Function Call 工具配置将在未来版本中提供。" |
| VL dialog section: Model | "Model" | "模型" |
| VL dialog section: Voice | "Voice" | "语音" |
| VL dialog section: Avatar | "Avatar" | "数字人" |
| VL dialog section: Conversation | "Conversation" | "对话" |
| VL dialog section: Agent | "Agent Instructions" | "Agent 指令" |
All copy is already externalized in i18n files (admin.json namespace, voiceLive.* and hcp.* keys).
- Create: Click "New Instance" -> VlInstanceDialog opens in create mode -> Fill 6 sections -> "Save" -> toast success -> dialog closes -> grid refreshes
- Edit: Click "Edit Instance" on card -> VlInstanceDialog opens with pre-filled values -> Modify -> "Save" -> toast success -> grid refreshes
- Delete: Click "Delete Instance" on card -> confirmation Dialog -> "Delete Instance" (destructive) -> toast success OR 409 conflict toast error
- Assign: Click "Assign to HCP" on card -> Select dialog with available HCPs -> "Assign to HCP" -> toast success
- Unassign: Expand HCP list on card -> click X next to HCP name -> instant unassign -> toast success
- View: Open HCP editor -> "Voice & Avatar" tab -> shows instance selector + read-only preview (or empty state)
- Assign instance: Select from dropdown -> immediate API call (for existing profiles) or form state update (for new profiles)
- Remove instance: Click X button -> confirmation Dialog -> "Remove Assignment" (destructive) -> form value cleared
-
Navigate: Click "Manage in Voice Live" link -> navigates to
/admin/voice-live
- Tab 1 "Profile": Existing identity/personality/knowledge/interaction fields
- Tab 2 "Voice & Avatar": Read-only VL instance reference (simplified from Phase 12)
- Tab 3 "Knowledge": Placeholder with BookOpen icon + future update notice
- Tab 4 "Tools": Placeholder with Wrench icon + future update notice
- All dialogs use Radix Dialog primitive with
onOpenChangefor close behavior - Dialogs close on: overlay click, ESC key, Cancel button, successful save
- Delete dialogs disable confirm button during
isPendingmutation - VlInstanceDialog disables Save when
nameis empty or duringisPending
| Breakpoint | VL Management Grid | Stat Cards | Dialog Width |
|---|---|---|---|
| Mobile (<640px) | 1 column | 2 columns | Full width with padding |
| Tablet (640-1024px) | 2 columns | 3 columns |
sm:max-w-2xl (672px) |
| Desktop (>1024px) | 3 columns | 3 columns |
sm:max-w-2xl (672px) |
HCP editor Voice tab: max-w-2xl (672px) constrains content width within the tab panel.
- All form controls have associated
Labelelements viahtmlFor/idpairs - Dialog titles use
DialogTitle(maps toaria-labelledby) - Dialog descriptions use
DialogDescription(maps toaria-describedby) - StatCards use
aria-labelwith value + label text - Avatar grid items are
<button>elements (keyboard navigable) - Selected avatar state communicated via visual ring (no
aria-pressed— defer to visual cue per existing pattern) - Delete/Remove buttons show tooltip via
titleattribute - Switch components use
id+Label htmlForpattern
| Registry | Blocks Used | Safety Gate |
|---|---|---|
| Project UI library (Radix wrappers) | Dialog, Select, Card, Button, Badge, Input, Label, Textarea, Switch, Slider, Tabs, Skeleton, ScrollArea, Form, Avatar | not required (in-project) |
| lucide-react | Plus, RefreshCw, Settings2, CheckCircle, Users, Pencil, Trash2, Mic, UserPlus, ChevronDown, ChevronUp, X, ExternalLink, Volume2, Monitor, ArrowLeft, Save, MessageSquare, BookOpen, Wrench | not required (npm package) |
No third-party registries used. No shadcn registry blocks. All components are project-internal.
- Dimension 1 Copywriting: PASS
- Dimension 2 Visuals: PASS
- Dimension 3 Color: PASS
- Dimension 4 Typography: PASS
- Dimension 5 Spacing: PASS
- Dimension 6 Registry Safety: PASS
Approval: pending