How the OpenMAIC VoiceDesign Interface Ensures Agent Voices Travel with Exported Courses
The OpenMAIC VoiceDesign interface ensures an agent’s voice travels with an exported course by serializing voice configuration metadata into the course bundle during export and re-hydrating that state on import.
The OpenMAIC platform manages AI-driven classroom environments where each course defines specific voice characteristics for both narrators and student agents. When instructors share or backup courses, preserving these audio preferences is critical for consistent learner experiences across different deployments. The VoiceDesign interface acts as a serializable container for all voice-related settings, embedding directly into the course metadata to guarantee that agent voices survive the export and import cycle.
The VoiceDesign Interface Structure
The foundation of voice portability in OpenMAIC begins with the VoiceDesign interface defined in lib/audio/voice-design.ts. This TypeScript interface establishes a standardized schema for voice configuration that captures every customizable audio element.
The interface defines four primary properties:
narratorVoice?: VoiceBinding– Specifies the default voice for the "teacher" or narrator roleagentVoiceOverrides?: Record<string, VoiceBinding>– Maps specific agent IDs to custom voice configurations, allowing individual student agents to speak with distinct voicesavailableVoices?: VoiceOption[]– Lists voice options available for UI presentation during course authoringvoiceDesignPrompt?: string– Carries optional prompts for backend voice registration services
export interface VoiceDesign {
/** The voice the narrator (the “teacher”) will use. */
narratorVoice?: VoiceBinding;
/** Per‑agent voice overrides (e.g. student agents). */
agentVoiceOverrides?: Record<string, VoiceBinding>;
/** The list of voices that the UI can present to the user. */
availableVoices?: VoiceOption[];
/** Optional prompt that can be sent to a backend that supports voice registration. */
voiceDesignPrompt?: string;
}
Because VoiceDesign is a plain JavaScript object without methods or circular references, it serializes cleanly to JSON without data loss, making it ideal for cross-platform course sharing.
Serializing Voice Data During Course Export
When a user initiates an export operation, the OpenMAIC workbench collects the current course state and packages it into a portable bundle. In lib/workbench/run-courses.ts, the exportCourse function constructs a JSON payload that includes a voiceDesign field copied directly from the workspace store.
The exporter accesses the current voice configuration through the store selector:
const voiceDesign = workspaceStore.getState().voiceDesign;
This object is embedded verbatim into the exported bundle. Since the VoiceDesign interface stores only primitive values and nested plain objects—such as providerId strings, voiceId identifiers, and custom prompts—all nested properties survive the JSON serialization process intact. The resulting export file contains a self-contained voice configuration that requires no external database references to reconstruct.
Re-Hydrating Voice Settings on Course Import
The import routine in the same lib/workbench/run-courses.ts file reverses the serialization process. The importCourse function reads the voiceDesign entry from the imported JSON bundle and writes it back into the workspace store via the voiceDesignSlice.
Once stored, selectors such as selectNarratorVoice and selectAgentVoiceOverrides immediately access the re-hydrated state. This means the UI renders the previously configured narrator voice and per-agent overrides without requiring manual reconfiguration. The course author can execute the imported course knowing that every agent will speak with the exact same voice characteristics defined on the original machine.
Runtime Voice Resolution and TTS Integration
During course execution, the runtime system resolves abstract voice bindings into actual TTS (Text-to-Speech) requests. The tts-stage-sync.ts module coordinates this process by calling helper functions from lib/audio/voice-resolver.ts:
resolveNarratorVoiceBinding– Retrieves the narrator voice from theVoiceDesigndataresolveAgentVoice– Looks up specific agent overrides or falls back to default provider settings
These resolvers read the same VoiceDesign payload that traveled with the exported course, ensuring consistent voice selection regardless of which machine executes the course. When the TTS stage generates speech, it embeds the resolved voice IDs into request payloads sent to providers like OpenAI TTS or Qwen TTS.
import { resolveNarratorVoiceBinding } from '@/lib/audio/voice-resolver';
const narrator = resolveNarratorVoiceBinding(
workspaceStore.getState().voiceDesign,
);
ttsStageSync.speak(text, narrator); // Uses the exported voice configuration
Implementing VoiceDesign in Practice
Creating a VoiceDesign Configuration
During course authoring, developers construct a VoiceDesign object and commit it to the workspace store:
import { VoiceDesign } from '@/lib/audio/voice-design';
const myVoiceDesign: VoiceDesign = {
narratorVoice: { providerId: 'openai-tts', voiceId: 'alloy' },
agentVoiceOverrides: {
student_1: { providerId: 'qwen-tts', voiceId: 'Cherry' },
},
availableVoices: [
{ providerId: 'openai-tts', voiceId: 'alloy', voiceName: 'Alloy' },
{ providerId: 'qwen-tts', voiceId: 'Cherry', voiceName: 'Cherry' },
],
};
workspaceStore.getState().setVoiceDesign(myVoiceDesign);
Exporting and Importing with Voice Preservation
The export operation automatically includes the voice design without additional configuration:
import { exportCourse } from '@/lib/workbench/run-courses';
const exportedBundle = await exportCourse({ courseId: 'my-course' });
// exportedBundle contains the voiceDesign field with all voice bindings
On the destination machine, importing the bundle restores the voice configuration:
import { importCourse } from '@/lib/workbench/run-courses';
await importCourse({ bundle: exportedBundle });
// Workspace store now contains the original voiceDesign state
Summary
The OpenMAIC VoiceDesign interface guarantees voice portability through a serializable metadata pattern:
lib/audio/voice-design.tsdefines the interface schema that captures narrator voices, agent overrides, and available optionslib/workbench/run-courses.tshandles export serialization and import re-hydration of thevoiceDesignfield- Plain JSON serialization ensures that provider IDs, voice IDs, and custom prompts survive the export/import cycle without data loss
lib/audio/voice-resolver.tsandtts-stage-sync.tsconsume the restored configuration at runtime to resolve actual TTS voices- Workspace store selectors provide immediate access to imported voice settings throughout the UI
Frequently Asked Questions
What happens if a voice provider ID in the exported course is not available on the import machine?
The resolveAgentVoice and resolveNarratorVoiceBinding functions in lib/audio/voice-resolver.ts implement fallback logic that defaults to provider-specific voices when the exact providerId or voiceId from the exported VoiceDesign is unavailable locally. This ensures the course remains functional even when specific voice models differ between environments.
Can individual student agents have different voices from the narrator?
Yes. The agentVoiceOverrides property in the VoiceDesign interface accepts a Record<string, VoiceBinding> map that assigns unique voice configurations to specific agent IDs. When the runtime resolves voices, it checks this override map before falling back to the narrator voice or system defaults.
Does the voice design include actual audio files or just voice identifiers?
The VoiceDesign interface stores only metadata—specifically providerId, voiceId, and optional configuration prompts—not actual audio data. The voice identifiers reference TTS services (such as OpenAI TTS or Qwen TTS) that generate audio on demand during course execution.
How does the UI know which voices to display during course authoring?
The availableVoices array within the VoiceDesign interface contains VoiceOption objects that populate the authoring interface dropdowns. When a course is imported, this array is restored from the exported bundle, ensuring the destination machine presents the same voice selection options that existed during original course creation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →