Commit Graph
6 Commits
Author SHA1 Message Date
bb8d4f30e7 feat(chat): add experimental Pi classroom runtime behind a flag (#914)
* feat(chat): add experimental Pi classroom runtime

* fix(chat): harden Pi whiteboard action sequencing

* style(chat): format session retirement flow

* style(playback): format async scene transition

* fix(chat): retire actions on session errors

* fix(chat): close Pi runtime lifecycle gaps

* fix(chat): avoid replaying historical whiteboard actions

* fix(chat): prevent Pi structured-output residue from leaking and inflating turns

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): expose whiteboard element/line ids and bound code-line context

Surface each element's id (and code line ids) in the Pi whiteboard context so
later child agents can target wb_delete / wb_edit_code, and cap the rendered
code lines with a shared character budget so a code-heavy board cannot grow the
prompt without bound. Return only the current turn's whiteboard ledger from the
Pi director loop instead of carrying history forward across requests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): bound Pi whiteboard code context

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): prioritize newer persisted whiteboard code in budget

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(chat): enforce whiteboard boundaries across Pi sessions

* feat(chat): refine soft-closing discussion controls

* fix(chat): make whiteboard clearing model-directed

---------

Co-authored-by: apple <apple@GigideMacBook-Air.local>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: LING-6150 <duan.lin@northeastern.edu>
2026-07-17 11:22:02 +08:00
wyucandClaude Opus 4.6 815cdc22fc fix: presentation mode bubble polish and TTS timing improvements (#244)
* fix: use fixed width for normal mode speech bubble to prevent streaming jitter

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add click-to-pause, AudioIndicator, and play/pause icon to presentation bubbles

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: anchor ProactiveCard to agent avatar in presentation mode dock

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: bubble click events, ProactiveCard anchor timing, and dock sidebar overlap

- Add pointer-events-auto to presentation bubbles so clicks pass through
- Use agent avatar ref directly for ProactiveCard anchor (removes fallback)
- Shift dock left when chat sidebar is open to prevent overlap

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: align presentation bubble icon with roundtable breathing bars and hover behavior

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent play/pause icon from overlapping bubble text

Add pr-10 padding to text area and align icon position with roundtable style.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace AudioIndicator bars with volume icon and loading spinner in presentation bubbles

Avoids visual conflict with the breathing bars play/pause icon at bottom-right.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace AudioIndicator bars with volume icon and loading spinner in roundtable bubbles

Syncs with presentation bubble style for consistency.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: add breathing opacity animation to volume icon during TTS playback

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: use ripple wave animation for volume icon during TTS playback

Three concentric rings expand outward from the volume icon to indicate
active audio playback. Replaces the opacity breathing animation.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent blank flash between same-agent speech segments

Only clear bubble text on agent_start when switching to a different agent.
Same-agent continuation keeps the previous text visible until the next
segment starts revealing, avoiding a lingering first bubble and blank gap.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent TTS queue from blocking text reveal across segment boundaries

The shouldHold() callback checked both isPlaying and queue.length, which
meant the buffer stayed stuck on segment 1's text while segment 2's TTS
was generating/playing. Now shouldHold() only checks isPlaying.

Also changed queueMicrotask to setTimeout(0) in audio.ended callbacks
so the StreamBuffer's 30ms tick has a chance to observe isPlaying=false
and release its hold before processQueue sets it back to true.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: release StreamBuffer hold per-segment instead of waiting for entire TTS queue

Previously, shouldHold() returned a single boolean based on global TTS
state (isPlaying || queue.length > 0). When speech was split into
multiple segments by an action, the buffer would hold on Segment 1's
text even after its audio finished, because Segment 2's audio started
immediately.

Now shouldHold() returns a segmentDone counter that increments each
time a segment finishes. The buffer snapshots this counter when hold
begins and releases as soon as it changes, allowing text to advance
to the next segment even if its audio is already queued.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: replace ripple circles with sound wave arcs on volume icon

Three SVG arcs emanate from the right side of the volume icon with
staggered opacity animation, resembling speaker sound waves.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: simplify volume icon to static display without animation

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: enable scrolling in presentation bubble when text overflows

Replace overflow-hidden with overflow-y-auto and scrollbar-hide to
maintain proper bottom padding when content exceeds max height.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: increase bottom padding and max height for presentation bubble text area

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: pause and resume TTS audio when discussion is paused/resumed

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: defer TTS playback when paused during generation

When discussion is paused while TTS is still fetching, the audio
element is created but not played. Resume will start it.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: check holding flag before segmentDone counter in TTS hold logic

The object returned by shouldHold is always truthy, so the falsy
release path was dead code. Now checks result.holding first: if
false (queue empty), release immediately. Only use segmentDone
counter comparison when holding is true.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: restore ProactiveCard anchor fallback to dock container

When agent avatar hasn't mounted yet, fall back to dock container
so the card can still position and render.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: stop TTS playback and abort active SSE stream on stage unmount

Previously, leaving a classroom while a discussion was active would
leave TTS audio playing and the API call streaming in the background.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: abort active SSE stream and shutdown buffers on chat sessions unmount

When navigating away from a classroom (e.g. clicking the back button),
the chat sessions hook now aborts any active API request and shuts
down all stream buffers. This prevents orphaned SSE connections and
runaway agent loops after leaving the stage.

Refs #236

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address code review feedback

- Reset pausedRef and segmentDoneCounterRef in cleanup() to prevent
  stale state on hook reuse
- Remove unused audioAgentColor prop from PresentationBubbleCard
- Capture chatAreaRef.current to local variable in Stage unmount effect

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:32:14 +08:00
Yizuki_AmeandYizukiAme 0533adbe82 feat: refine presentation mode speech bubbles, input flow, and accessibility (#195)
* feat: add presentation mode with fullscreen, idle-hide, and keyboard navigation

- Fullscreen via toolbar button or F11; exit via ESC/F11/button
- Header auto-hides, sidebars collapse, slide fills viewport
- Idle auto-hide (3s): toolbar/avatars fade out, speech bubble stays visible
- Smart suspension: idle-hide pauses during typing/recording/voice input
- Keyboard navigation: Arrow keys (prev/next), Space (play/pause), ESC (exit)
feat: add presentation mode with fullscreen, idle-hide, and keyboard navigation

- Fullscreen via toolbar button or F11; exit via ESC/F11/button
- Header auto-hides, sidebars collapse, slide fills viewport
- Idle auto-hide (3s): toolbar/avatars fade out, speech bubble stays visible
- Smart suspension: idle-hide pauses during typing/recording/voice input
- Keyboard navigation: Arrow keys (prev/next), Space (play/pause), ESC (exit)
- F11 intercepted to use Fullscreen API (ESC-friendly) instead of browser native
- Whiteboard hints reposition from bottom to top corners in fullscreen
- i18n: fullscreen/exitFullscreen keys (zh-CN + en-US)

Closes #102

.git/COMMIT_EDITMSG [unix] (14:47 22/03/2026)                                                                    1,1 Top
feat: add presentation mode with fullscreen, idle-hide, and keyboard navigation

- Fullscreen via toolbar button or F11; exit via ESC/F11/button
- Header auto-hides, sidebars collapse, slide fills viewport
- Idle auto-hide (3s): toolbar/avatars fade out, speech bubble stays visible
- Smart suspension: idle-hide pauses during typing/recording/voice input
- Keyboard navigation: Arrow keys (prev/next), Space (play/pause), ESC (exit)
- F11 intercepted to use Fullscreen API (ESC-friendly) instead of browser native
- Whiteboard hints reposition from bottom to top corners in fullscreen
- i18n: fullscreen/exitFullscreen keys (zh-CN + en-US)

Closes #102

.git/COMMIT_EDITMSG [unix] (14:47 22/03/2026)                                                                    1,1 Top
- F11 intercepted to use Fullscreen API (ESC-friendly) instead of browser native
- Whiteboard hints reposition from bottom to top corners in fullscreen
- i18n: fullscreen/exitFullscreen keys (zh-CN + en-US)

Closes #102

* feat: refine presentation mode speech bubbles, input flow, and accessibility

- User messages now display as right-side speech bubbles for send confirmation
- 'Your turn' cue is a clickable glass button respecting ASR preference
- Cue properly excludes bubbleRole/thinkingState to avoid UI overlap
- Right-side dock + bubble uses flexbox for dynamic stacking
- Voice-to-text switch now stops recording to prevent mic leaks
- Backdrop no longer blocks toolbar (bottom-14 cutoff)
- User message clears immediately when agent starts responding
- Dock buttons and avatar have proper aria-labels and button semantics
- Voice panel mic trigger converted from div to button with aria-label
- Added 5 i18n keys (zh-CN + en-US) for new accessible labels
- matchesSide typed as boolean, removed unused userAvatar from left overlay
- Avatar alt text localized via i18n

Refs #102

* fix: address code review audit  cancel ghost sends, consolidate getAgentConfig, fix a11y

* fix: guard concurrent voice recording and suppress cancel error toast

* style: vertically center placeholder text in presentation input bar

* style: full light-mode adaptation for presentation UI, toolbar dividers, bubble opacity 60%

* chore: address #129 follow-up  remove orphan i18n keys, clarify waitUntilDrained pause behavior

* fix: resolve spacebar conflict and address review feedback

- Stage: skip Space during active QA/discussion (let Roundtable own
  buffer-level pause); deterministic, no listener-order dependency
- Stage: wrap handlePlayPause in useCallback([playbackCompleted,
  currentScene]) to avoid keyboard listener re-registration
- Stage: clear presentationIdleTimerRef on unmount
- PresentationBubbleCard: add aria-live='polite' for screen readers
- Extract shared avatar constants to roundtable/constants.ts

* style: format with prettier

* fix: render ProactiveCard inside fullscreen container via portalContainer prop

* feat: show requesting agent avatar in dock on discussion request

---------

Co-authored-by: YizukiAme <yizukiame@github.com>
2026-03-24 13:04:55 +08:00
ddb52241fb feat: add Discussion TTS with per-agent voice assignment (#211)
* feat(tts): add resolveVoice() and getServerVoiceList() utilities

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(tts): add AudioIndicator equalizer bars component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(tts): add onSegmentSealed callback to StreamBuffer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(tts): add voiceOverrides field to AgentConfig and AgentTemplate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(tts): add useDiscussionTTS hook with audio queue and cleanup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): add audio state indicator to Roundtable bubble

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(tts): wire onSegmentSealed callback through chat sessions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): add per-agent voice dropdown to AgentBar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): integrate useDiscussionTTS in Stage and pass state to Roundtable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(tts): refine voice dropdown to pill-style selector

Replace native select styling with a compact rounded-full pill
that blends into the agent row. Remove border, use muted bg,
smaller text, and a custom chevron icon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(tts): use shadcn Select for voice dropdown, link with TTS toggle

- Replace native <select> with shadcn Select component for consistent UI
- Hide voice dropdown when TTS is muted (ttsMuted)
- Compact pill-style trigger with rounded-full, no border, muted bg

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(tts): add voice label prefix and always show dropdown

Show "音色: Alloy" instead of plain "Alloy" in the voice pill.
Always show dropdown regardless of mute state (voice config is
independent of playback).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(tts): add volume icon hint in collapsed AgentBar

Show a small Volume2 icon in the collapsed pill when voice config
is available, hinting that voice settings are inside.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): fix voice dropdown layout and click handling

- Move voice pill below agent name (second line) to prevent
  horizontal overflow in English
- Wrap Select in div with onPointerDown stopPropagation to fix
  Radix click-through to parent row
- Add line-clamp-1 to descriptions for consistent row height
- Use items-start instead of items-center for better multi-line alignment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(tts): redesign AgentBar voice layout for compactness

- Single-line layout: checkbox · avatar · name · role · voice pill
- Remove descriptions from agent rows (saves vertical space)
- Extract AgentVoicePill component to isolate Select event handling
- Smaller avatars (size-7), tighter row padding (py-1.5)
- Voice pill uses Volume2 icon + voice name (no prefix text)
- Works in both Chinese and English without overflow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): cross-provider voice selection per agent

- Change voiceConfig from per-provider lookup to explicit
  { providerId, voiceId } per agent
- Each agent can use a different TTS provider's voice
- Voice picker dropdown groups voices by provider
- useDiscussionTTS routes TTS requests per agent's provider
- resolveAgentVoice falls back to global provider if no config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): align role badge and voice pill across agent rows

Give role badge fixed width (w-14 text-right) so role text
and voice pills align vertically across all rows regardless
of agent name length.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): fix role badge and voice pill alignment

Wrap role badge + voice pill in a fixed-width container
(w-[9.5rem] justify-end) so both align vertically across
all agent rows regardless of name or role text length.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(tts): align role badge and voice pill across agent rows

Add min-w-[52px] text-right to role badge so it starts at a
consistent position regardless of agent name length.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): use fixed w-[60px] for role badge alignment

* fix(tts): use fixed w-[88px] for voice pill alignment

* fix(tts): prevent click-outside from closing AgentBar when Select portal is open

* fix(tts): comprehensive voice picker rewrite

- Replace Radix Select with Popover + button list (fixes click issue)
- Fix getAvailableProvidersWithVoices to always include global provider
- Widen panel from w-80 to w-96 (prevents name truncation)
- Voice pill uses primary color instead of gray (more visible)
- Extract renderAgentRow helper to reduce duplication
- Popover shows voices grouped by provider with active state
- Add findVoiceDisplayName utility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): align voice provider availability with toolbar logic

* fix(tts): fallback to first available provider when global provider has no voices

* refactor(tts): remove global provider fallback from voice resolution

Voice resolution now only depends on available providers (those with
API keys or server-configured). No more globalProviderId parameter.
Fallback is first available provider, then browser-native-tts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): add browser native TTS voices to agent voice picker

Load speechSynthesis.getVoices() in AgentBar and include as a
"Browser Native" provider group in the voice popover. No API key
needed - always available if browser supports it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): simplify toolbar TTS to on/off toggle, add disabled state

Toolbar:
- Replace volume slider with simple TTS on/off toggle button
- Remove ttsMuted/ttsVolume/onVolumeChange props from CanvasToolbar
- Toggle now controls ttsEnabled (not ttsMuted)

AgentBar:
- Collapsed: show VolumeX icon when TTS disabled
- Voice pills show disabled state (gray, cursor-not-allowed, no popover)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(tts): simplify Settings TTS tab to toggle + provider config

Remove voice selection, speed slider, preview/test, Azure locale
filter from Settings TTS tab. Voice is now per-agent in AgentBar.
Keep: on/off toggle, provider selector, API key + base URL config.
Add hint text pointing to AgentBar for voice configuration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(tts): simplify media popover TTS tab to toggle only

* fix(tts): add voice config hint to media popover TTS tab

* feat(tts): add per-voice preview button in voice picker

Each voice row in the popover has a small speaker icon button.
Click to preview the voice with "欢迎来到AI课堂" / "Welcome to
AI Classroom" (follows i18n). Browser native uses Web Speech API,
server TTS calls /api/generate/tts. Click again or close popover
to stop. Shows spinner while generating.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): preview text follows course language instead of UI language

* refactor(tts): redesign AgentBar expanded panel layout

- Teacher always at top with voice pill (works in both modes)
- Mode tabs moved below teacher
- Auto mode: single compact row with shuffle icon + description
- Max turns: compact inline row with smaller input
- Preset mode: only student agents listed (teacher already above)
- Remove large shuffle animation from auto mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(tts): merge max turns into teacher row

* refactor(tts): separate teacher row and max turns, use stepper UI

- Teacher row: avatar + name + voice pill only
- Max turns: bottom row with MessageSquare icon + compact stepper
  (minus/number/plus in a rounded pill)
- Remove Input component dependency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): increase voice pill contrast in dark mode

* fix(tts): make max turns input editable, tighten panel padding

* fix(tts): restore shuffle animation in auto mode (compact version)

* fix(tts): adjust auto mode text spacing and add voice auto-assign hint

* fix(tts): auto-close voice popover after selecting a voice

* fix(tts): increase auto mode vertical padding for better balance

* fix(tts): push auto mode text toward bottom with flex spacer

* fix(tts): reduce auto mode bottom padding

* feat(tts): wait for TTS audio to finish before next agent turn

Add waitForDrain() to useDiscussionTTS that returns a promise
resolving when the audio queue is empty. The agent loop in
useChatSessions now awaits this after buffer drain, so the next
agent's turn doesn't start until the current agent's TTS audio
finishes playing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): keep bubble visible while TTS audio is still playing

When buffer drains (text=null) but audio indicator is still active,
don't clear liveSpeech. Clear it only when audio state goes idle.
This keeps the speech bubble visible until TTS finishes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): hold discussion bubble until TTS audio finishes

When StreamBuffer fires the done signal (onLiveSpeech null), Stage
now checks if TTS is still playing. If so, it defers clearing the
bubble state. The bubble stays visible until onAllAudioEnd fires
from the TTS hook (queue empty + nothing playing), then clears.

This prevents the jarring UX where the bubble disappears while
the agent's voice is still audible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): fix bubble hold - guard onStopSession instead of onLiveSpeech

Root cause: bubble disappears because doSessionCleanup fires via
onStopSession when the agent loop ends naturally, NOT because of
onLiveSpeech(null, null).

Fix: when onStopSession fires and TTS is still playing, defer
doSessionCleanup to onAllAudioEnd callback. Manual stop (user
presses button) still cleans up immediately via handleStopDiscussion.

Use doSessionCleanupRef to avoid circular dependency between
discussionTTS hook and doSessionCleanup useCallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): guard BOTH onLiveSpeech and onStopSession for bubble hold

Two paths clear the bubble:
1. onLiveSpeech(null, null) from StreamBuffer done → clears liveSpeech
2. onStopSession → doSessionCleanup → clears all state

Both fire when agent loop ends. Path 1 fires first (tick loop),
path 2 fires after (waitUntilDrained resolves). Both must be
guarded when TTS is still playing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): hold bubble during TTS playback and respect playback speed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(tts): LLM picks voice matching agent persona during generation

- Client sends available voices (providerId + voiceId + name) to
  /api/generate/agent-profiles
- LLM prompt asks to pick a voice matching each agent's personality
- Parse "providerId::voiceId" from response, save as voiceConfig
- Fallback to index-based assignment if LLM doesn't pick
- Browser native voices hidden when server providers are available
- saveGeneratedAgents accepts and persists voiceConfig

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): restore volume slider in classroom toolbar

Revert the toolbar simplification from 36e3997 that replaced the
volume slider with a TTS on/off toggle. The volume control with
hover slider is a core classroom UX. TTS on/off is controlled via
Settings and Media popover instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): teacher uses global lecture voice in discussion when no voiceConfig override

* fix(tts): teacher always uses global lecture voice, no overrides

* fix(tts): sync playback speed to currently playing audio in real-time

* fix(tts): address code review issues

- Issue 2: enabled flag now checks ttsEnabled && !ttsMuted in stage.tsx
- Issue 4: remove unused browserAvailableVoices from useDiscussionTTS
- Issue 5: remove dead code in audio-settings.tsx (Slider, Loader2, handleTTSVoiceChange, handleTTSSpeedChange, handleTestTTS, testingTTS, ttsTestStatus, ttsTestMessage, testText, ttsSpeed, setTTSSpeed, and unused browser-tts-preview imports)
- Issue 6: shouldHold now checks queue length in addition to isPlayingRef
- Issue 8: hide AgentVoicePill for teacher row in agent-bar.tsx (teacher voice is controlled in Settings)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(tts): address PR review — abort preview fetch, defer error recovery

1. Add AbortController to voice preview server TTS fetch, abort on
   stopPreview to prevent stale responses on rapid switching
2. Use queueMicrotask for processQueue calls in error/ended handlers
   to prevent synchronous recursion if multiple items fail consecutively
3. Add ordering invariant comment on sealLastText's onSegmentSealed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(tts): restore teacher voice pill, respect voiceConfig override

* fix(tts): sync volume and mute to discussion TTS audio in real-time

* fix(tts): allow browser-native TTS alongside server providers

* fix(tts): remove top padding from voice popover content

* fix(tts): make selectedAgents reactive to voiceConfig changes

* fix(tts): use agents record instead of listAgents() to avoid infinite loop

* fix(tts): single source of truth for teacher voice

Teacher voice pill now reads/writes global ttsProviderId + ttsVoice
(same settings used by lecture TTS). This ensures lecture and
discussion always use the same teacher voice. Student agents still
use per-agent voiceConfig.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add avatar descriptions for smarter LLM avatar selection

Each avatar now has a one-line description (appearance, vibe) sent
to the agent-profiles generation API. LLM picks avatars matching
agent personality instead of guessing from file paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com>
2026-03-23 17:35:09 +08:00
wyucandClaude Opus 4.6 843d33e5cc chore: enforce Prettier formatting and fix lint issues
- Add .prettierignore to exclude vendor packages, lock files, markdown, and YAML
- Update .prettierrc: printWidth 100, singleQuote, trailingComma "all"
- Run Prettier across all source files for consistent formatting
- Fix unused imports (UserRequirements, setTTSProvider)
- Fix eslint-disable comment placement after Prettier reformat

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:09:45 +08:00
wyucandClaude Opus 4.6 0d20abfed9 Initial commit: OpenMAIC AI classroom platform
Next.js 16 App Router application with:
- AI-powered interactive classroom generation from PDF/text requirements
- Multi-agent discussion system (teacher, students, assistant roles)
- Provider abstraction for LLM, TTS, ASR, image, video, web search
- Local-first data architecture (IndexedDB/Dexie)
- i18n support (zh-CN/en-US)
- Structured logger, SSRF guard, lint/build passing (0 errors)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:41:07 +08:00