Planning Phase 15 - huqianghui/AI-Coach-vibe-coding GitHub Wiki
Auto-generated from
.planning/phases/15-hcp-editor-agent-config-center
Last synced: 2026-04-28
Gathered: 2026-04-07 Status: Ready for planning Source: PRD Express Path (/Users/huqianghui/.claude/plans/deep-foraging-hammock.md)
## Phase Boundary重构 HCP 编辑器页面为 Agent 配置中心,对齐 Azure AI Foundry Agent 编辑体验:
- 移除空 Knowledge 和 Tools tab(Phase 14-03 添加的占位符)
- Voice & Avatar tab 升级为完整 Agent 配置中心布局
- 左侧面板:Model Deployment + Voice Mode 开关 + Instructions + Knowledge & Tools 配置
- 右侧面板:Playground 预览(数字人/音波球 + Start 测试 + Transcript)
前提:Phase 14 已完成 VL Instance CRUD、HCP Voice Tab 只读预览、unassign endpoint 等基础设施。
## Implementation Decisions- 移除 Knowledge 和 Tools 两个空 tab(从 hcp-profile-editor.tsx 删除 tab trigger + content)
- 保留 Profile tab(HCP 基本信息)
- Voice & Avatar tab 重构为 Agent 配置中心
- Model Deployment 选择器: 下拉 + 自定义输入(类似 Azure Foundry 截图 Image #3 gpt-5.4-mini 风格)
-
Voice Mode 开关: "Switch the agent to a voice-first experience"
- 开启时显示 VL Instance 选择器(复用已有 hooks)
- 关闭时隐藏 voice 配置
-
Instructions 区域:
- 自动生成的 instructions(基于 profile 数据调用 build_agent_instructions)
- 可编辑 override(agent_instructions_override 字段)
- 魔法棒按钮重新生成
-
Knowledge & Tools 配置:
- Knowledge: 文件上传 / 知识库配置(内联在 tab 中,不是独立 tab)
- Tools: 工具配置(内联在 tab 中,不是独立 tab)
- 根据 avatar_enabled 显示数字人形象或音波球
- Start 测试按钮(复用 VL Instance Editor 的测试逻辑)
- 对话 transcript 区域
-
to_prompt_dict()需要包含agent_instructions_override - 确保 build_agent_instructions 正确读取 override
- 新增 GET endpoint 获取 auto-generated instructions preview
- 添加 model deployment、voice mode 开关、instructions 等新 keys
- 中英文双语(en-US + zh-CN)
- Knowledge & Tools 内联区域的具体 UI 组件实现细节
- Playground 预览面板的音波球动画效果
- Instructions 自动生成的 API 调用时机(实时 vs 按需)
<canonical_refs>
Downstream agents MUST read these before planning or implementing.
-
frontend/src/pages/admin/hcp-profile-editor.tsx— 主编辑页面(572行,当前 4 tab) -
frontend/src/components/admin/voice-avatar-tab.tsx— 当前 Voice & Avatar tab(Phase 14 已简化为只读预览) -
frontend/src/components/admin/agent-status-section.tsx— Agent 状态显示
-
frontend/src/types/hcp.ts— HCP TypeScript 类型定义 -
frontend/src/hooks/use-hcp-profiles.ts— HCP Query hooks -
frontend/src/hooks/use-voice-live.ts— Voice Live WebSocket hook -
frontend/src/hooks/use-voice-live-instances.ts— VL Instance CRUD hooks
-
backend/app/services/agent_sync_service.py— build_agent_instructions() -
backend/app/models/hcp_profile.py— HCP ORM 模型(含 agent_instructions_override) -
backend/app/schemas/hcp_profile.py— Pydantic schemas -
backend/app/services/voice_live_websocket.py— WebSocket 代理
frontend/public/locales/en-US/admin.jsonfrontend/public/locales/zh-CN/admin.json
- Image #3: Model deployment 选择器(gpt-5.4-mini)
- Image #4: Instructions 区域(自动生成 + 可编辑)
- Image #5: 数字人形象 + Start 测试按钮(Azure Foundry 风格)
</canonical_refs>
## Specific Ideas- 对齐 Azure AI Foundry Agent 编辑体验 — Model Deployment + Instructions + Playground 三栏布局
- Voice Mode 开关模式 — 参考 Azure Foundry "Switch to voice-first experience" toggle
- Instructions 魔法棒 — 调用 build_agent_instructions 实时预览 auto-generated instructions
- Knowledge & Tools 内联 — 不作为独立 tab,而是 Voice & Avatar tab 内的折叠区域
- Knowledge 区域的完整文件上传功能(可先做 UI 框架,后端集成后续 phase)
- Tools 区域的完整 Function Call 配置(可先做 UI 框架)
- Playground 的完整实时对话功能(先做 UI 结构 + Start 按钮)
Phase: 15-hcp-editor-agent-config-center Context gathered: 2026-04-07 via PRD Express Path
| # | Plan File | Status |
|---|---|---|
| 15-01 | 15-01-PLAN.md | Complete |
| 15-02 | 15-02-PLAN.md | Complete |
| 15-03 | 15-03-PLAN.md | Complete |
Click to expand research notes
Researched: 2026-04-07 Domain: React frontend refactoring + FastAPI backend endpoint + i18n Confidence: HIGH
Phase 15 is a frontend-heavy refactoring phase that transforms the HCP Profile Editor's tab structure to align with Azure AI Foundry's Agent editing experience. The core work involves: (1) removing two placeholder tabs (Knowledge, Tools), (2) rebuilding the Voice & Avatar tab as a two-panel Agent configuration center with left-side controls and right-side Playground preview, and (3) adding a new backend endpoint to preview auto-generated instructions.
The codebase already has nearly all building blocks in place. The VL Instance Editor page (vl-instance-editor.tsx) implements a nearly identical Playground pattern with AvatarView, AudioOrb, useVoiceLive, useAvatarStream, useAudioHandler, and transcript display. The VoiceLiveModelSelect component provides tiered model selection. The build_agent_instructions function in agent_sync_service.py handles instruction generation with override priority. The only net-new backend work is a preview endpoint that calls build_agent_instructions with profile form data and returns the generated text.
Primary recommendation: Extract the Playground preview panel from vl-instance-editor.tsx into a reusable component, then compose the new Voice & Avatar tab as a left-right split layout importing existing components (VoiceLiveModelSelect, VL Instance selector, Instructions textarea, and the new Playground panel).
<user_constraints>
- Tab structure: remove Knowledge and Tools tabs, keep Profile and Voice & Avatar only
- Voice & Avatar tab left panel: Model Deployment selector, Voice Mode toggle + VL Instance selector, Instructions area (auto-generate + editable override), Knowledge & Tools inline config
- Voice & Avatar tab right panel: Playground preview (avatar/audio orb + Start button + transcript)
- Backend: to_prompt_dict() must include agent_instructions_override; new GET endpoint for instructions preview
- i18n: new keys for model deployment, voice mode toggle, instructions area (en-US + zh-CN)
- Knowledge & Tools inline section UI component details
- Playground audio orb animation effect
- Instructions auto-generation API call timing (realtime vs on-demand)
- Knowledge area full file upload functionality (UI skeleton only, backend integration later)
- Tools area full Function Call configuration (UI skeleton only)
- Playground full real-time conversation functionality (UI structure + Start button first) </user_constraints>
<phase_requirements>
| ID | Description | Research Support |
|---|---|---|
| HCP-15-01 | HCP editor has only Profile and Voice & Avatar tabs (Knowledge/Tools removed) | Direct code change in hcp-profile-editor.tsx lines 285-554 -- remove 2 TabsTrigger + 2 TabsContent blocks and unused imports |
| HCP-15-02 | Voice & Avatar tab left panel: Model Deployment + Voice Mode toggle + VL Instance + Instructions | Reuse VoiceLiveModelSelect, existing VL Instance assign/unassign hooks, existing agent_instructions_override form field; new preview endpoint |
| HCP-15-03 | Voice & Avatar tab right panel: Playground preview with avatar/orb + Start + transcript | Extract from vl-instance-editor.tsx (lines 248-367) -- AvatarView, AudioOrb, useVoiceLive, useAvatarStream, useAudioHandler already exist |
| HCP-15-04 | Instructions magic wand button calls build_agent_instructions to regenerate | New backend POST /{profile_id}/preview-instructions endpoint calling build_agent_instructions; frontend hook + button |
| HCP-15-05 | Tests + i18n (en-US + zh-CN) + TypeScript compilation passes | Follow existing test patterns; add i18n keys to both locale files |
| </phase_requirements> |
| Library | Version | Purpose | Why Standard |
|---|---|---|---|
| React | 18.3+ | UI framework | Project standard [VERIFIED: codebase] |
| react-hook-form | existing | Form state management | Used across all admin forms [VERIFIED: codebase] |
| zod | existing | Schema validation | Used with zodResolver in HCP editor [VERIFIED: codebase] |
| @tanstack/react-query | ^5.60 | Server state + mutations | Project standard [VERIFIED: codebase] |
| react-i18next | existing | i18n framework | Project standard since Phase 1 [VERIFIED: codebase] |
| lucide-react | ^0.460 | Icons (Wand2, Play, etc.) | Project icon library [VERIFIED: codebase] |
| FastAPI | >=0.115 | Backend API | Project standard [VERIFIED: codebase] |
| Component | Location | Purpose | Reuse Strategy |
|---|---|---|---|
| VoiceLiveModelSelect | components/admin/voice-live-model-select.tsx |
Tiered model dropdown | Import directly |
| AudioOrb | components/voice/audio-orb.tsx |
Voice-only animation | Import directly |
| AvatarView | components/voice/avatar-view.tsx |
Avatar video + fallback | Import directly |
| useVoiceLive | hooks/use-voice-live.ts |
WebSocket proxy hook | Import directly |
| useAvatarStream | hooks/use-avatar-stream.ts |
WebRTC avatar stream | Import directly |
| useAudioHandler | hooks/use-audio-handler.ts |
Mic input capture | Import directly |
| useAudioPlayer | hooks/use-audio-player.ts |
Audio playback | Import directly |
| VoiceControls | components/voice/voice-controls.tsx |
Mute/disconnect buttons | Import directly |
| useVoiceLiveInstances | hooks/use-voice-live-instances.ts |
VL Instance CRUD hooks | Import directly |
| AVATAR_CHARACTER_MAP | data/avatar-characters.ts |
Avatar metadata | Import directly |
Installation: No new packages required. This phase only uses existing dependencies. [VERIFIED: codebase analysis]
frontend/src/
├── pages/admin/
│ └── hcp-profile-editor.tsx # Modified: remove Knowledge/Tools tabs
├── components/admin/
│ ├── voice-avatar-tab.tsx # REWRITE: 2-panel agent config center
│ ├── agent-config-left-panel.tsx # NEW: left panel (model, voice mode, instructions)
│ ├── playground-preview-panel.tsx # NEW: right panel (avatar/orb + start + transcript)
│ └── instructions-section.tsx # NEW: auto-gen + override + magic wand
├── hooks/
│ └── use-hcp-profiles.ts # Modified: add usePreviewInstructions hook
└── api/
└── hcp-profiles.ts # Modified: add previewInstructions API call
What: Voice & Avatar tab uses CSS Grid with grid-cols-1 lg:grid-cols-2 for responsive left-right split.
When to use: Admin editor pages that need both configuration controls and live preview.
Example:
// Source: existing pattern from vl-instance-editor.tsx
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="space-y-4"> {/* Left: Config controls */}
<AgentConfigLeftPanel />
</div>
<div className="sticky top-4"> {/* Right: Playground preview */}
<PlaygroundPreviewPanel />
</div>
</div>What: Display auto-generated instructions text, allow user to type an override, provide magic wand button to re-generate. When to use: When system prompt is derived from structured data but users may want customization. Backend flow:
# Source: agent_sync_service.py build_agent_instructions() [VERIFIED: codebase]
# 1. If agent_instructions_override is non-empty -> return override
# 2. Otherwise -> format DEFAULT_AGENT_TEMPLATE with profile dataFrontend flow:
- On tab load, call
GET /api/v1/hcp-profiles/{id}/preview-instructionsto get auto-generated text - Show in read-only textarea (collapsed/dimmed when override is active)
- Override textarea bound to
agent_instructions_overrideform field - Magic wand button: re-call preview endpoint, show result in auto-gen area
What: Extract test session logic from vl-instance-editor.tsx into a reusable Playground component.
Why: The VL Instance Editor page (lines 248-367) already implements the complete pattern: useVoiceLive + useAvatarStream + useAudioHandler + transcript accumulation + start/stop logic. The HCP editor needs the exact same functionality.
Interface:
interface PlaygroundPreviewPanelProps {
hcpProfileId?: string;
vlInstanceId?: string;
systemPrompt?: string;
avatarCharacter?: string;
avatarStyle?: string;
avatarEnabled: boolean;
disabled?: boolean; // true for new profiles (no id yet)
}-
Duplicating Playground code: Do NOT copy-paste the test session logic from
vl-instance-editor.tsx. Extract into a shared component. -
Inlining useQuery in components: Follow project convention -- all queries go through hooks in
hooks/directory. [VERIFIED: CLAUDE.md rule] -
Static route ordering violation: Any new endpoint added to
hcp_profiles.pymust come BEFORE/{profile_id}routes. Addpreview-instructionsroute afterbatch-syncbut before/{profile_id}. [VERIFIED: CLAUDE.md Gotcha #3]
| Problem | Don't Build | Use Instead | Why |
|---|---|---|---|
| Model tier dropdown | Custom select with tiers |
VoiceLiveModelSelect component |
Already groups models by Pro/Standard/Lite tiers with i18n [VERIFIED: codebase] |
| Audio visualization | CSS animation from scratch |
AudioOrb component |
Already matches AI Foundry style with listening/speaking states [VERIFIED: codebase] |
| Avatar preview | Manual video element management |
AvatarView component |
Handles WebRTC video, static thumbnail fallback, AudioOrb fallback [VERIFIED: codebase] |
| Voice Live WebSocket | Raw WebSocket code |
useVoiceLive hook |
Complete proxy flow with reconnect, transcript, audio delta [VERIFIED: codebase] |
| VL Instance assignment | Custom mutation logic |
useAssignVoiceLiveInstance / useUnassignVoiceLiveInstance hooks |
Already handle cache invalidation for both VL and HCP query keys [VERIFIED: codebase] |
| Instructions generation | Frontend string templating | Backend build_agent_instructions()
|
Server-side generation ensures consistency with agent sync [VERIFIED: codebase] |
Key insight: This phase is primarily a UI restructuring and composition phase. Nearly every functional building block already exists in the codebase. The risk is in duplicating rather than reusing existing components.
What goes wrong: The CONTEXT.md explicitly calls out that to_prompt_dict() needs to include agent_instructions_override. Currently it does NOT (verified in hcp_profile.py lines 84-100).
Why it happens: to_prompt_dict() was originally designed for system prompt construction and predates the override field.
How to avoid: Add agent_instructions_override to the return dict in to_prompt_dict(). The build_agent_instructions function already checks for it (line 62-63 of agent_sync_service.py).
Warning signs: Instructions preview always returns template-generated text, never the override.
What goes wrong: New route /{profile_id}/preview-instructions added after /{profile_id} gets shadowed by the /{profile_id} route.
Why it happens: FastAPI matches the first route that fits the pattern.
How to avoid: Place the new endpoint after batch-sync (line 161) but before /{profile_id} (line 120). Better yet, use a path like POST /{profile_id}/preview-instructions which won't conflict because it uses POST and has a sub-path.
Warning signs: 404 or wrong handler executing.
What goes wrong: Switching between Profile and Voice & Avatar tabs loses form state.
Why it happens: If Form wrapper doesn't encompass both tabs.
How to avoid: The current architecture already wraps <Form {...form}> around <Tabs> (line 276 of hcp-profile-editor.tsx). This pattern MUST be preserved. [VERIFIED: codebase decision from Phase 12]
Warning signs: Data entered in one tab disappears when switching.
What goes wrong: Clicking Start on a new (unsaved) profile attempts WebSocket connection with no profile ID.
Why it happens: New profiles have isNew=true and no database ID.
How to avoid: Disable the Start button when isNew is true. Show helper text: "Save profile first to test."
Warning signs: WebSocket errors or empty sessions.
What goes wrong: Building full file upload / function call UI instead of placeholder skeleton. Why it happens: The CONTEXT.md's decision section mentions Knowledge & Tools inline config, but the Deferred section explicitly marks full functionality as out of scope. How to avoid: Build collapsible sections with descriptive placeholder content only. No actual upload/API integration. Warning signs: Sprint overrun, blocked on unbuilt backend features.
What goes wrong: TypeScript compilation fails due to unused imports (BookOpen, Wrench) after removing Knowledge/Tools tabs.
Why it happens: Tab placeholder components imported icons that are no longer needed.
How to avoid: Clean up imports when removing tab content. npx tsc -b will catch these. [VERIFIED: CLAUDE.md pre-commit checklist]
Warning signs: Build failures in CI.
# Source: pattern derived from agent_sync_service.build_agent_instructions [VERIFIED: codebase]
# Place AFTER /batch-sync but BEFORE /{profile_id} routes
class InstructionsPreviewRequest(BaseModel):
"""Profile data for instructions generation preview."""
name: str = ""
specialty: str = ""
hospital: str = ""
title: str = ""
personality_type: str = "friendly"
emotional_state: int = 50
communication_style: int = 50
expertise_areas: list[str] = []
prescribing_habits: str = ""
concerns: str = ""
objections: list[str] = []
probe_topics: list[str] = []
difficulty: str = "medium"
agent_instructions_override: str = ""
class InstructionsPreviewResponse(BaseModel):
"""Generated instructions text."""
instructions: str
is_override: bool
@router.post("/preview-instructions", response_model=InstructionsPreviewResponse)
async def preview_instructions(
body: InstructionsPreviewRequest,
user: User = Depends(require_role("admin")),
):
"""Preview auto-generated agent instructions from profile data. Admin only."""
from app.services.agent_sync_service import build_agent_instructions
profile_data = body.model_dump()
instructions = build_agent_instructions(profile_data)
is_override = bool(body.agent_instructions_override and body.agent_instructions_override.strip())
return InstructionsPreviewResponse(instructions=instructions, is_override=is_override)// Source: composition pattern from vl-instance-editor.tsx [VERIFIED: codebase]
export function VoiceAvatarTab({ form, profile, isNew }: VoiceAvatarTabProps) {
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Left Panel: Configuration */}
<div className="space-y-4">
<AgentConfigLeftPanel form={form} profile={profile} isNew={isNew} />
</div>
{/* Right Panel: Playground Preview */}
<div>
<PlaygroundPreviewPanel
hcpProfileId={profile?.id}
vlInstanceId={form.watch("voice_live_instance_id") ?? undefined}
systemPrompt={form.watch("agent_instructions_override") ?? ""}
avatarCharacter={form.watch("avatar_character")}
avatarStyle={form.watch("avatar_style")}
avatarEnabled={!!form.watch("avatar_character")}
disabled={isNew}
/>
</div>
</div>
);
}// Source: pattern derived from existing form fields + new preview hook [VERIFIED: codebase]
import { Wand2 } from "lucide-react";
function InstructionsSection({ form, profileId }: { form: UseFormReturn<HcpFormValues>; profileId?: string }) {
const { t } = useTranslation("admin");
const [autoInstructions, setAutoInstructions] = useState("");
const [isGenerating, setIsGenerating] = useState(false);
const handleGenerate = async () => {
setIsGenerating(true);
try {
const formValues = form.getValues();
const result = await previewInstructions(formValues);
setAutoInstructions(result.instructions);
} finally {
setIsGenerating(false);
}
};
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle className="text-sm">{t("admin:hcp.autoInstructions")}</CardTitle>
<Button variant="ghost" size="sm" onClick={handleGenerate} disabled={isGenerating}>
<Wand2 className="size-4 mr-1" />
{isGenerating ? "..." : t("common:generate")}
</Button>
</div>
</CardHeader>
<CardContent className="space-y-3">
{autoInstructions && (
<pre className="text-xs bg-muted/50 rounded p-3 max-h-48 overflow-y-auto whitespace-pre-wrap">
{autoInstructions}
</pre>
)}
<FormField
control={form.control}
name="agent_instructions_override"
render={({ field }) => (
<FormItem>
<FormLabel>{t("admin:hcp.overrideInstructions")}</FormLabel>
<FormControl>
<Textarea rows={4} placeholder={t("admin:hcp.overridePlaceholder")} {...field} />
</FormControl>
</FormItem>
)}
/>
</CardContent>
</Card>
);
}| Old Approach | Current Approach | When Changed | Impact |
|---|---|---|---|
| 4 tabs (Profile, Voice & Avatar, Knowledge, Tools) | 2 tabs (Profile, Agent Config Center) | Phase 15 | Knowledge/Tools become inline sections in Voice & Avatar |
| Voice & Avatar tab = read-only VL preview (303 lines) | Voice & Avatar tab = full Agent config center (left+right panels) | Phase 15 | Major rewrite of voice-avatar-tab.tsx
|
| No instructions preview API | POST /preview-instructions endpoint | Phase 15 | Enables magic wand button for instruction regeneration |
to_prompt_dict() excludes override |
to_prompt_dict() includes agent_instructions_override
|
Phase 15 | Fixes data flow for instruction preview |
Deprecated/outdated:
- Knowledge tab placeholder (added Phase 14-03, removed Phase 15)
- Tools tab placeholder (added Phase 14-03, removed Phase 15)
| # | Claim | Section | Risk if Wrong |
|---|---|---|---|
| A1 |
Wand2 icon exists in lucide-react ^0.460 for the magic wand button |
Code Examples | LOW -- fallback to Sparkles or RefreshCw icon if not available |
| A2 | POST method for preview-instructions won't conflict with existing route patterns | Architecture | LOW -- POST to a static path before /{profile_id} is unambiguous |
| A3 | Knowledge & Tools inline sections should be collapsible Card components with placeholder content | Architecture | LOW -- CONTEXT.md says "inline in tab, not independent tab"; UI details are Claude's Discretion |
-
Instructions generation timing
- What we know: The magic wand button calls backend on-demand (CONTEXT.md: Claude's Discretion area)
- What's unclear: Should auto-generated instructions load automatically when tab opens (initial load), or only when user clicks the wand?
- Recommendation: Load on tab mount for existing profiles (cheap GET call), require explicit click for new profiles. This provides immediate feedback while keeping UX responsive.
-
Playground test scope
- What we know: CONTEXT.md says "Start test button (reuse VL Instance Editor test logic)" and Deferred says "full real-time conversation first phase = UI structure + Start button"
- What's unclear: Should the Start button actually connect to Voice Live (full test), or just show UI skeleton?
- Recommendation: Implement full Start/Stop functionality by extracting from
vl-instance-editor.tsx. The hooks already exist and the code is proven. Only defer if Azure credentials are not configured (show appropriate message).
-
Playground preview for new profiles
- What we know: New profiles have no ID, can't test
- What's unclear: Should we show a static avatar preview image even without a live connection?
- Recommendation: Show static avatar thumbnail based on selected
avatar_character+avatar_stylefrom form state, with disabled Start button and helper text.
Step 2.6: SKIPPED (no external dependencies identified -- this phase is code/config changes only using existing project dependencies).
| ASVS Category | Applies | Standard Control |
|---|---|---|
| V2 Authentication | no | -- |
| V3 Session Management | no | -- |
| V4 Access Control | yes |
require_role("admin") on new endpoint [VERIFIED: all HCP endpoints use this] |
| V5 Input Validation | yes | Pydantic schema validation on preview request body [VERIFIED: existing pattern] |
| V6 Cryptography | no | -- |
| Pattern | STRIDE | Standard Mitigation |
|---|---|---|
| Unauthorized instructions preview | Elevation of Privilege |
require_role("admin") dependency [VERIFIED: codebase] |
| XSS via instructions override text | Tampering | React auto-escapes JSX; Textarea value is text-only [VERIFIED: React default] |
- Codebase analysis of all files listed in CONTEXT.md canonical_refs -- verified current state of every component
-
hcp-profile-editor.tsx(572 lines) -- current 4-tab structure, Form wrapping Tabs -
voice-avatar-tab.tsx(307 lines) -- current read-only VL preview, will be rewritten -
vl-instance-editor.tsx(~700+ lines) -- Playground test pattern to extract -
agent_sync_service.py(565 lines) --build_agent_instructionsfunction -
hcp_profile.py(100 lines) --to_prompt_dict()missing override field -
hcp_profiles.pyAPI router -- route ordering, existing endpoints
- Project STATE.md accumulated decisions -- confirmed Form-wraps-Tabs pattern (Phase 12), VoiceAvatarTab rewrite (Phase 14)
Confidence breakdown:
- Standard stack: HIGH - all components already exist in codebase, no new dependencies
- Architecture: HIGH - pattern directly extracted from existing vl-instance-editor.tsx
- Pitfalls: HIGH - identified from concrete codebase analysis (route ordering, form state, missing field)
Research date: 2026-04-07 Valid until: 2026-05-07 (stable -- internal refactoring phase, no external API changes)
Click to expand UI spec
Visual and interaction contract for the HCP Editor Agent Config Center phase. Generated by gsd-ui-researcher, verified by gsd-ui-checker.
| Property | Value |
|---|---|
| Tool | none (Radix UI wrappers, no shadcn CLI) |
| Preset | not applicable |
| Component library | Radix UI (via existing components/ui/ wrappers) |
| Icon library | lucide-react ^0.460 |
| Font | Inter + Noto Sans SC (sans), JetBrains Mono (mono) |
Source: Pre-populated from codebase analysis (frontend/src/styles/index.css, frontend/src/components/ui/). Project has been using this stack since Phase 01.
Declared values (must be multiples of 4):
| Token | Value | Usage |
|---|---|---|
| xs | 4px | Icon-to-label gap inside buttons, inline icon padding |
| sm | 8px | Compact element spacing within form groups, badge padding |
| md | 16px | Default gap between form fields, card internal padding |
| lg | 24px | Gap between left/right panels, section spacing within panels |
| xl | 32px | Top-level tab content margin, page header padding |
| 2xl | 48px | Empty state vertical padding (Knowledge/Tools placeholder area) |
| 3xl | 64px | Not used in this phase |
Exceptions:
- Playground preview panel avatar/orb container uses 240px min-height (fixed to match VL Instance Editor pattern in
vl-instance-editor.tsx) - Touch target for Start/Stop test button: 44px height minimum (accessibility)
| Role | Size | Weight | Line Height | Usage in This Phase |
|---|---|---|---|---|
| Body | 16px (--text-base) | 400 (--font-weight-normal) | 1.5 | Form field values, transcript text, instructions body |
| Label | 14px (--text-sm) | 500 (--font-weight-medium) | 1.5 | Form labels, section headers, card titles |
| Heading | 18px (--text-lg) | 500 (--font-weight-medium) | 1.5 | Tab names, panel titles ("Agent Configuration", "Playground") |
| Code | 12px (--text-xs) | 400 (--font-weight-normal) | 1.5 | Auto-generated instructions preview (monospace --font-mono) |
Source: Pre-populated from frontend/src/styles/index.css base layer rules (lines 252-297). Matches project-wide typography contract established in Phase 01.
| Role | Value | Usage |
|---|---|---|
| Dominant (60%) | var(--background) / #FFFFFF | Page background, tab content area, form field backgrounds |
| Secondary (30%) | var(--card) / #FFFFFF with var(--border) | Card surfaces for left panel sections, right panel playground container |
| Accent (10%) | var(--primary) / #1E40AF | See reserved list below |
| Destructive | var(--destructive) / #EF4444 | Disconnect/stop test button when active |
| Muted | var(--muted) / #F9FAFB | Auto-generated instructions preview background, disabled form fields |
| Voice Listening | var(--voice-listening) / #A855F7 | AudioOrb ring when recording mic input |
| Voice Speaking | var(--voice-speaking) / #22C55E | AudioOrb ring when AI is speaking |
Accent reserved for:
- "Save" button (primary CTA)
- "Start" test button in Playground panel
- Voice Mode toggle switch when enabled (on state)
- Magic wand (regenerate instructions) button icon on hover
- Active tab indicator underline
- VL Instance link badge when connected
| Component | File | Description |
|---|---|---|
| AgentConfigLeftPanel | components/admin/agent-config-left-panel.tsx |
Left panel container: Model Deployment + Voice Mode + Instructions + Knowledge/Tools inline |
| PlaygroundPreviewPanel | components/admin/playground-preview-panel.tsx |
Right panel: avatar/orb display + Start/Stop + transcript |
| InstructionsSection | components/admin/instructions-section.tsx |
Auto-generated preview + editable override + magic wand button |
| Component | File | Changes |
|---|---|---|
| VoiceAvatarTab | components/admin/voice-avatar-tab.tsx |
Full rewrite: 2-panel grid layout (left config, right playground) |
| hcp-profile-editor | pages/admin/hcp-profile-editor.tsx |
Remove Knowledge/Tools tabs (2 TabsTrigger + 2 TabsContent), remove unused imports (BookOpen, Wrench) |
| Component | Source | Used For |
|---|---|---|
| VoiceLiveModelSelect | components/admin/voice-live-model-select.tsx |
Model Deployment dropdown with tiered groups |
| AudioOrb | components/voice/audio-orb.tsx |
Voice-only animation in Playground |
| AvatarView | components/voice/avatar-view.tsx |
Digital human video + fallback in Playground |
| VoiceControls | components/voice/voice-controls.tsx |
Mute/disconnect in Playground test session |
| Switch | components/ui/switch.tsx |
Voice Mode on/off toggle |
| Card/CardHeader/CardContent/CardTitle | components/ui/card.tsx |
Section containers in left panel |
| Textarea | components/ui/textarea.tsx |
Instructions override editor |
| Button | components/ui/button.tsx |
Magic wand, Start/Stop, Save |
| Select | components/ui/select.tsx |
VL Instance selector dropdown |
| Badge | components/ui/badge.tsx |
VL Instance connection status |
| Separator | components/ui/separator.tsx |
Section dividers in left panel |
+------------------------------------------------------------------+
| [Profile Tab] [Voice & Avatar Tab (active)] |
+------------------------------------------------------------------+
| LEFT PANEL (config) | RIGHT PANEL (playground) |
| 50% width on lg+ | 50% width on lg+ |
| 100% width on mobile | 100% width on mobile (stacks) |
| | |
| +-- Model Deployment ------+ | +-- Playground ----------------+ |
| | [tiered model dropdown] | | | | |
| +--------------------------+ | | [AvatarView or AudioOrb] | |
| | | 240px min-height | |
| +-- Voice Mode ------------+ | | | |
| | [toggle switch] | | | [Start / Stop button] | |
| | [VL Instance selector] | | | | |
| | (visible when enabled) | | | +-- Transcript -----------+ | |
| +--------------------------+ | | | [scrollable chat log] | | |
| | | | 200px max-height | | |
| +-- Instructions ----------+ | | +--------------------------+ | |
| | [auto-gen preview (ro)] | | +-------------------------------+ |
| | [magic wand button] | | |
| | [override textarea] | | |
| +--------------------------+ | |
| | |
| +-- Knowledge & Tools -----+ | |
| | [collapsible section] | | |
| | [placeholder content] | | |
| +--------------------------+ | |
+------------------------------------------------------------------+
CSS Grid: grid grid-cols-1 lg:grid-cols-2 gap-6
Left panel: space-y-4 for vertical section stacking
Right panel: sticky top-4 for scroll-following on large screens
| Tab | Value | Content |
|---|---|---|
| Profile | profile |
HCP identity, personality, objections, difficulty (unchanged) |
| Voice & Avatar | voice-avatar |
Agent Config Center (new 2-panel layout) |
Removed tabs: knowledge, tools (were placeholders from Phase 14-03)
| Property | Specification |
|---|---|
| Component |
VoiceLiveModelSelect (reused) |
| Default value |
gpt-4o (from existing VOICE_LIVE_MODEL_OPTIONS) |
| Bound form field | voice_live_model |
| Behavior | Dropdown with Pro/Standard/Lite tier groups |
| Property | Specification |
|---|---|
| Component |
Switch from components/ui/switch.tsx
|
| Label | "Switch the agent to a voice-first experience" (i18n key: admin:hcp.voiceModeToggle) |
| Default state | OFF for new profiles, derived from voice_live_instance_id presence for existing |
| When ON | Show VL Instance selector dropdown below the toggle |
| When OFF | Hide VL Instance selector; clear voice_live_instance_id from form |
| VL Instance selector |
Select component with available instances from useVoiceLiveInstances hook |
| Property | Specification |
|---|---|
| Auto-generated preview | Read-only pre block, bg-muted/50 rounded p-3, text-xs font-mono, max-height 192px with overflow-y-auto |
| Override textarea |
Textarea component, 4 rows, bound to agent_instructions_override form field |
| Magic wand button |
Button variant="ghost" size="sm" with Wand2 icon from lucide-react |
| API call timing | Existing profiles: auto-load on tab mount via POST /api/v1/hcp-profiles/preview-instructions. New profiles: load only on wand click. |
| Loading state | Wand button shows spinner icon while generating, disabled during request |
| Empty state | When no auto-generated instructions yet, show muted text: "Click the wand to generate instructions from profile data" |
| Property | Specification |
|---|---|
| Layout | Single collapsible Card at bottom of left panel |
| Header | "Knowledge & Tools" with ChevronRight/ChevronDown toggle icon |
| Default state | Collapsed |
| Expanded content | Two sub-sections with placeholder content (no functional backend) |
| Knowledge placeholder | FileText icon (12px muted) + "Knowledge base configuration coming soon" |
| Tools placeholder | Wrench icon (12px muted) + "Function Call tools configuration coming soon" |
| Scope | UI skeleton only. No file upload, no API integration. (Deferred per CONTEXT.md) |
| Property | Specification |
|---|---|
| Container | Card with CardHeader title "Playground" |
| Avatar/Orb area | 240px min-height centered container. Show AvatarView if avatar_character is selected, else show AudioOrb. |
| Start button |
Button with Play icon, centered below avatar/orb area. Label: "Start" (i18n). Disabled when isNew === true or no VL Instance assigned. |
| Stop button | Replaces Start when test is active. Button variant="destructive" with Square icon. Label: "Stop". |
| Disabled helper | When button is disabled, show muted text below: "Save profile and assign a Voice Live instance to test" |
| Transcript area | Scrollable div, 200px max-height, bg-muted/30 rounded, displays TranscriptSegment[] with role labels (User/Agent) |
| Voice controls |
VoiceControls component shown during active test (mute toggle) |
| Connection | Reuse useVoiceLive + useAvatarStream + useAudioHandler hooks (extracted pattern from vl-instance-editor.tsx) |
[New Profile]
-> Playground: Start disabled, helper text shown
-> Instructions: Wand click only (no auto-load)
-> Voice Mode: Toggle available but no persistence until save
[Saved Profile, No VL Instance]
-> Playground: Start disabled, "Assign VL Instance to test"
-> Instructions: Auto-load on tab mount
-> Voice Mode: OFF
[Saved Profile, VL Instance Assigned]
-> Playground: Start enabled
-> Instructions: Auto-load on tab mount
-> Voice Mode: ON with instance shown
[Playground Test Active]
-> Start button -> Stop button
-> VoiceControls visible (mute)
-> Transcript accumulates in real-time
-> Avatar/Orb shows speaking/listening state
-> Other form fields remain editable
[Playground Test Stopped]
-> Stop button -> Start button
-> Transcript preserved (not cleared until next Start)
-> VoiceControls hidden
| Element | en-US | zh-CN | i18n Key |
|---|---|---|---|
| Tab label | Voice & Avatar | 语音与数字人 |
admin:hcp.tabVoiceAvatar (existing) |
| Model Deployment section title | Model Deployment | 模型部署 |
admin:hcp.modelDeployment (new) |
| Voice Mode toggle label | Switch to voice-first experience | 切换到语音优先体验 |
admin:hcp.voiceModeToggle (new) |
| Voice Mode description | Enable Voice Live for real-time voice interaction with this agent | 启用 Voice Live 实现与此 Agent 的实时语音交互 |
admin:hcp.voiceModeDescription (new) |
| VL Instance label | Voice Live Instance | Voice Live 实例 |
admin:hcp.vlInstanceLabel (new) |
| VL Instance empty | No instance assigned | 未分配实例 |
admin:hcp.vlInstanceNone (new) |
| Instructions auto title | Auto-generated Instructions | 自动生成指令 |
admin:hcp.autoInstructions (existing) |
| Instructions override label | Override Instructions | 自定义指令 |
admin:hcp.overrideInstructions (existing) |
| Instructions override placeholder | Leave empty to use auto-generated instructions | 留空则使用自动生成的指令 |
admin:hcp.overridePlaceholder (existing) |
| Instructions generate hint | Click the wand to generate instructions from profile data | 点击魔法棒从 Profile 数据生成指令 |
admin:hcp.instructionsHint (new) |
| Generate button | Generate | 生成 |
common:generate (new) |
| Regenerate button | Regenerate | 重新生成 |
common:regenerate (new) |
| Knowledge & Tools header | Knowledge & Tools | 知识库与工具 |
admin:hcp.knowledgeAndTools (new) |
| Knowledge placeholder | Knowledge base configuration coming soon | 知识库配置即将推出 |
admin:hcp.knowledgePlaceholder (new) |
| Tools placeholder | Function Call tools configuration coming soon | Function Call 工具配置即将推出 |
admin:hcp.toolsPlaceholder (new) |
| Playground title | Playground | 工作台 |
admin:hcp.playgroundTitle (new) |
| Playground start | Start | 开始 |
admin:hcp.playgroundStart (new) |
| Playground stop | Stop | 停止 |
admin:hcp.playgroundStop (new) |
| Playground disabled (new profile) | Save profile first to test | 请先保存 Profile 后再测试 |
admin:hcp.playgroundDisabledNew (new) |
| Playground disabled (no VL) | Assign a Voice Live instance to test | 请分配 Voice Live 实例后再测试 |
admin:hcp.playgroundDisabledNoVl (new) |
| Transcript user label | You | 你 |
admin:hcp.transcriptUser (new) |
| Transcript agent label | Agent | Agent |
admin:hcp.transcriptAgent (new) |
| Primary CTA | Save Profile | 保存 Profile |
admin:hcp.save (existing) |
| Error: instructions generation failed | Failed to generate instructions. Check profile data and try again. | 生成指令失败,请检查 Profile 数据后重试 |
admin:hcp.instructionsError (new) |
| Error: test connection failed | Voice Live connection failed | Voice Live 连接失败 |
admin:hcp.testConnectionError (new) |
Total new i18n keys: 17 (both en-US and zh-CN) Existing reused i18n keys: 6
| Breakpoint | Layout |
|---|---|
| < 1024px (mobile/tablet) | Single column: left panel stacks above right panel. Playground scrolls below config. |
| >= 1024px (lg desktop) | Two-column grid: left panel 50%, right panel 50% with sticky top-4. |
Tab bar: Full-width TabsList with 2 tabs (Profile, Voice & Avatar), each flex-1.
| Element | Requirement |
|---|---|
| Voice Mode toggle |
Switch component with aria-label from i18n key |
| Magic wand button |
aria-label="Generate instructions" from i18n |
| Start/Stop button |
aria-label toggles between "Start voice test" and "Stop voice test" |
| Instructions preview |
role="log" on auto-generated instructions container |
| Transcript panel |
role="log" with aria-live="polite" for real-time updates |
| Keyboard navigation | All interactive elements reachable via Tab key; Enter/Space to activate |
| Color contrast | All text meets WCAG AA (4.5:1 for body, 3:1 for large text) -- inherited from design token system |
| Registry | Blocks Used | Safety Gate |
|---|---|---|
| No shadcn CLI | N/A | N/A |
| No third-party registries | N/A | N/A |
This phase uses only existing Radix UI wrapper components from frontend/src/components/ui/. No new component library installations or registry imports required.
- 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
Click to expand verification report
Phase Goal: Refactor HCP editor to Agent Config Center aligned with Azure AI Foundry Agent editing experience. Remove empty Knowledge/Tools tabs, upgrade Voice & Avatar tab to full Agent config layout: Model Deployment selector, Voice Mode toggle + VL Instance binding, auto-generated + editable override Instructions, right-side Playground preview panel (digital human/audio orb + Start test).
Verified: 2026-04-07T10:15:00Z Status: human_needed Re-verification: No -- initial verification
| # | Truth | Status | Evidence |
|---|---|---|---|
| 1 | HCP editor has only Profile and Voice & Avatar tabs (Knowledge/Tools removed) | VERIFIED |
hcp-profile-editor.tsx has exactly 2 <TabsTrigger> (profile, voice-avatar), 2 <TabsContent>. No value="knowledge" or value="tools". No BookOpen or Wrench imports. VALID_TABS fallback set at line 116. |
| 2 | Voice & Avatar tab left panel: Model Deployment + Voice Mode toggle + VL Instance + Instructions | VERIFIED |
agent-config-left-panel.tsx (294 lines) contains VoiceLiveModelSelect, Switch for Voice Mode, Select for VL Instance with assign/unassign mutation hooks, InstructionsSection composition, Knowledge & Tools collapsible skeleton. |
| 3 | Voice & Avatar tab right panel: Playground preview with avatar/orb + Start + transcript | VERIFIED |
playground-preview-panel.tsx (302 lines) contains AvatarView/AudioOrb conditional rendering, Start/Stop buttons with session state machine (idle/connecting/connected/error/stopping), transcript area with role="log" aria-live="polite", MAX_TRANSCRIPTS=100 cap. |
| 4 | Instructions magic wand calls build_agent_instructions to regenerate | VERIFIED |
instructions-section.tsx contains Wand2 button calling previewInstructions API -> backend POST /preview-instructions -> build_agent_instructions. AbortController race guard confirmed. Override precedence verified: non-empty override returns directly, empty triggers auto-generation. |
| 5 | Frontend + backend tests, i18n (en-US + zh-CN), TypeScript compilation | VERIFIED | 9 backend tests (TestPreviewInstructionsEndpoint 6 + TestToPromptDictOverride 2 + TestPreviewInstructionsRouteOrder 1). 11 frontend structural tests. 19 Phase 15 i18n keys present in both locales. generate/regenerate keys in common.json for both locales. |
Score: 5/5 truths verified
| Artifact | Expected | Status | Details |
|---|---|---|---|
backend/app/api/hcp_profiles.py |
POST /preview-instructions endpoint | VERIFIED | Lines 164-205: InstructionsPreviewRequest, InstructionsPreviewResponse models + endpoint with require_role("admin") and build_agent_instructions call |
backend/app/models/hcp_profile.py |
to_prompt_dict includes agent_instructions_override | VERIFIED | Line 100: "agent_instructions_override": self.agent_instructions_override in return dict |
frontend/src/components/admin/agent-config-left-panel.tsx |
AgentConfigLeftPanel component | VERIFIED | 294 lines, exports AgentConfigLeftPanel with Model Deployment, Voice Mode, VL Instance assign/unassign (migrated from voice-avatar-tab.tsx), InstructionsSection, Knowledge & Tools |
frontend/src/components/admin/instructions-section.tsx |
InstructionsSection with AbortController | VERIFIED | 153 lines, abortControllerRef, handleGenerate with abort/recreate pattern, Wand2 button, auto-gen preview + override textarea |
frontend/src/components/admin/playground-preview-panel.tsx |
PlaygroundPreviewPanel with session state machine | VERIFIED | 302 lines, SessionState type, useVoiceLive/useAvatarStream/useAudioHandler/useAudioPlayer hooks, NotAllowedError mic permission handling, unmount cleanup useEffect, profile change cleanup useEffect |
frontend/src/components/admin/voice-avatar-tab.tsx |
Two-panel grid layout | VERIFIED | 34 lines, thin composition: grid grid-cols-1 lg:grid-cols-2 gap-6 composing AgentConfigLeftPanel + PlaygroundPreviewPanel |
frontend/src/pages/admin/hcp-profile-editor.tsx |
2 tabs only, legacy fallback | VERIFIED | 545 lines, VALID_TABS Set, handleTabChange fallback, Form wraps Tabs (line 284 before 285), no BookOpen/Wrench imports |
backend/tests/test_hcp_profiles_api.py |
Tests for preview-instructions | VERIFIED | TestPreviewInstructionsEndpoint (6 tests), TestToPromptDictOverride (2 tests), TestPreviewInstructionsRouteOrder (1 test) |
frontend/src/__tests__/hcp-editor-tabs.test.tsx |
Frontend structural tests | VERIFIED | 181 lines, 11 tests covering i18n parity, tab structure, lifecycle safeguards, AbortController |
frontend/src/api/hcp-profiles.ts |
previewInstructions with AbortSignal | VERIFIED | Lines 117-127: previewInstructions function with signal?: AbortSignal parameter |
frontend/src/hooks/use-hcp-profiles.ts |
usePreviewInstructions hook | VERIFIED | Line 85: usePreviewInstructions mutation hook |
frontend/public/locales/en-US/admin.json |
Phase 15 i18n keys | VERIFIED | 19 keys present (modelDeployment, playgroundTitle, permissionDeniedMic, etc.) |
frontend/public/locales/zh-CN/admin.json |
Phase 15 i18n keys (Chinese) | VERIFIED | 19 keys present with Chinese translations |
frontend/public/locales/en-US/common.json |
generate/regenerate keys | VERIFIED | Lines 55-56: generate, regenerate |
frontend/public/locales/zh-CN/common.json |
generate/regenerate keys (Chinese) | VERIFIED | Lines 55-56: Chinese translations |
| From | To | Via | Status | Details |
|---|---|---|---|---|
| voice-avatar-tab.tsx | agent-config-left-panel.tsx | import AgentConfigLeftPanel | WIRED | Line 2: import, Line 18: JSX usage in grid left cell |
| voice-avatar-tab.tsx | playground-preview-panel.tsx | import PlaygroundPreviewPanel | WIRED | Line 3: import, Line 22-29: JSX usage in grid right cell with form.watch props |
| agent-config-left-panel.tsx | instructions-section.tsx | import InstructionsSection | WIRED | Line 35: import, Line 225-229: JSX composition with form, profileId, isNew props |
| instructions-section.tsx | /api/v1/hcp-profiles/preview-instructions | previewInstructions API call with AbortController | WIRED | Line 15: import previewInstructions, Line 42+70: called with form.getValues() and controller.signal |
| hcp_profiles.py | agent_sync_service.py | build_agent_instructions import | WIRED | Line 199: inline import, Line 202: called with body.model_dump() |
| agent-config-left-panel.tsx | use-voice-live-instances.ts | assign/unassign VL instance hooks | WIRED | Lines 36-40: import useVoiceLiveInstances, useAssignVoiceLiveInstance, useUnassignVoiceLiveInstance; Lines 73-115: handleInstanceChange + handleConfirmRemove logic |
| hcp-profile-editor.tsx | voice-avatar-tab.tsx | VoiceAvatarTab composition | WIRED | Line 34: import, Line 525: JSX usage in TabsContent |
| Artifact | Data Variable | Source | Produces Real Data | Status |
|---|---|---|---|---|
| instructions-section.tsx | autoInstructions | previewInstructions API -> build_agent_instructions | Yes -- calls backend endpoint that runs template generation | FLOWING |
| agent-config-left-panel.tsx | instances | useVoiceLiveInstances() | Yes -- fetches from /api/v1/voice-live-instances | FLOWING |
| playground-preview-panel.tsx | transcripts | onTranscript callback from useVoiceLive | Yes -- populated by WebSocket events during active session | FLOWING (when connected) |
| Behavior | Command | Result | Status |
|---|---|---|---|
| Backend import succeeds | python3 -c "from app.api.hcp_profiles import router, InstructionsPreviewRequest, InstructionsPreviewResponse" |
All imports successful | PASS |
| InstructionsPreviewRequest model validates | python3 -c "...InstructionsPreviewRequest(name='Test', specialty='Oncology')" |
Model created with correct values | PASS |
| to_prompt_dict includes override | python3 -c "...HcpProfile(...).to_prompt_dict()" |
agent_instructions_override present in dict | PASS |
| Override precedence: override wins | build_agent_instructions({..., agent_instructions_override: 'Custom'}) |
Returns 'Custom override text' directly | PASS |
| Override precedence: empty triggers auto-gen | build_agent_instructions({..., agent_instructions_override: ''}) |
Returns text containing 'Dr. Test' and 'Oncology' | PASS |
| Route not shadowed | POST route order analysis | /preview-instructions at position 3, no bare POST /{profile_id} before it | PASS |
| Requirement | Source Plan | Description | Status | Evidence |
|---|---|---|---|---|
| HCP-15-01 | 15-02 | HCP editor has only Profile and Voice & Avatar tabs (Knowledge/Tools removed) | SATISFIED | hcp-profile-editor.tsx: 2 TabsTrigger, 2 TabsContent, no knowledge/tools values |
| HCP-15-02 | 15-01 | Voice & Avatar tab left panel: Model Deployment + Voice Mode toggle + VL Instance + Instructions | SATISFIED | agent-config-left-panel.tsx: VoiceLiveModelSelect, Switch, Select + assign/unassign, InstructionsSection |
| HCP-15-03 | 15-02 | Voice & Avatar tab right panel: Playground preview with avatar/orb + Start + transcript | SATISFIED | playground-preview-panel.tsx: AvatarView/AudioOrb, Start/Stop, transcript area, session state machine |
| HCP-15-04 | 15-01 | Instructions magic wand button calls build_agent_instructions to regenerate | SATISFIED | instructions-section.tsx: Wand2 button -> previewInstructions API -> build_agent_instructions |
| HCP-15-05 | 15-01, 15-03 | Tests + i18n (en-US + zh-CN) + TypeScript compilation passes | SATISFIED | 9 backend + 11 frontend tests, 19+2 i18n keys in both locales, TypeScript compiles per summary |
| File | Line | Pattern | Severity | Impact |
|---|---|---|---|---|
| agent-config-left-panel.tsx | 252, 256 |
knowledgePlaceholder / toolsPlaceholder i18n keys referencing "coming soon" text |
Info | Intentional non-functional skeleton per phase scope. Knowledge & Tools deferred to future phases. Not a stub -- explicit placeholder with i18n. |
Test: Open HCP editor, click Voice & Avatar tab, verify the two-panel responsive grid layout Expected: Left panel shows Model Deployment, Voice Mode toggle, VL Instance selector, Instructions section, Knowledge & Tools. Right panel shows Playground with avatar/orb area, Start button, transcript. Why human: Visual layout, responsive behavior, and UX alignment with Azure AI Foundry style cannot be verified programmatically
Test: Click magic wand button in Instructions section on an existing HCP profile Expected: Auto-generated instructions appear in preview area containing profile name and specialty Why human: End-to-end flow through backend endpoint requires running server and human observation
Test: Toggle Voice Mode switch ON/OFF Expected: VL Instance selector appears/disappears, form value cleared on toggle off Why human: Interactive toggle behavior requires visual confirmation
Test: Enter data on Profile tab, switch to Voice & Avatar, switch back Expected: Form data persists across tab switches Why human: State persistence across UI interactions needs human observation
Test: Switch language to zh-CN and navigate to HCP editor Voice & Avatar tab Expected: All new labels display in Chinese (model deployment, voice mode, playground, etc.) Why human: Translation quality and completeness requires visual inspection
Test: Navigate directly to HCP editor URL with ?tab=knowledge or ?tab=tools Expected: Falls back to Profile tab without console errors Why human: URL-based navigation testing requires browser interaction
No code-level gaps found. All 5 observable truths verified with full artifact existence, substantive implementation, wiring, and data-flow confirmation. All 5 phase requirements (HCP-15-01 through HCP-15-05) satisfied.
6 items require human visual verification before the phase can be marked as fully passed -- all relate to interactive UI behavior and visual layout that cannot be assessed through static code analysis or programmatic checks.
Verified: 2026-04-07T10:15:00Z Verifier: Claude (gsd-verifier)