How the OpenMAIC Lesson Generation Pipeline Is Structured: A Deep Dive into the Agent-Runtime Architecture
The OpenMAIC lesson generation pipeline is structured as a five-layer server-side orchestration system that parses user prompts into skill requests, dispatches them through specialized generation tools, persists incremental progress in Dexie-based stores, and synchronizes completion states with the React frontend for crash-resilient lesson construction.
The THU-MAIC/OpenMAIC repository implements a robust lesson generation pipeline within its agent-runtime architecture. This system transforms natural language prompts into structured educational content by chaining together stateless orchestration logic and persistent client-side state stores. Understanding this architecture reveals how the application maintains data integrity and UI responsiveness during long-running AI generation tasks.
Layer 1: Skill Parsing and Dispatch
The pipeline initiates in lib/server/agent-runtime/skill-handle-inference.ts, where the system parses incoming user prompts to extract the leading skill name.
When a user submits a prompt like "build a lesson about photosynthesis using slide-craft", the skill resolver identifies the tool identifier (e.g., slide-craft or stage-design) and forwards the request to the appropriate generation handler. This separation of concerns ensures that the orchestration layer remains agnostic to the specific content generation logic, treating each skill as a modular plugin.
Layer 2: Generation Tool Orchestration
The central registry in lib/server/agent-runtime/generation-tools.ts manages all generation implementations through the runGenerationTool entry point.
This orchestrator performs three critical operations:
- It creates a generation job with a unique
generationId. - It assigns the
producerfield as"server-job"to track ownership. - It records the job in the media-generation store before execution begins.
The registry maintains a generationToolMap that maps tool names (like slide-design or image-generation) to their respective execution handlers. This pattern allows developers to register new lesson-generation capabilities by extending the tool map without modifying the core dispatch logic.
// lib/server/agent-runtime/generation-tools.ts
export async function runGenerationTool(
toolName: GenerationToolName,
payload: GenerationPayload,
) {
const job = await createGenerationJob(toolName, payload); // creates DB record
const tool = generationToolMap[toolName];
await tool.execute(job.id, payload);
return job.id;
}
Layer 3: Persistent State Management
The pipeline delegates state persistence to two specialized Dexie-based stores that serve as the single source of truth for generation progress.
Media-Generation Store
Located in lib/store/media-generation.ts, this IndexedDB store tracks the granular state of every active generation job. It stores the outline, intermediate scene data, media URLs, and completion flags. The store provides methods like addChunk to stream incremental updates from the server, enabling real-time progress visualization even during lengthy AI inference.
// lib/store/media-generation.ts
export const useMediaGenerationStore = create<DexieStore<MediaGenerationRecord>>({
// Dexie schema …
async addChunk(jobId, chunk) {
await db.mediaGeneration.where('jobId').equals(jobId).modify({ ...chunk });
},
});
Stage Store
The lib/store/stage-store.ts maintains the current lesson's high-level metadata, including the scene list and the generationComplete boolean flag. When the orchestrator finishes processing, it writes the final outline into this store, triggering the UI to transition from loading states to content rendering. This store also handles crash-recovery by rehydrating the lesson state from IndexedDB when the application reloads.
Layer 4: Frontend Synchronization
React components consume the pipeline state through custom hooks (useMediaGenerationStore, useStageStore). The components/generation/interactive-mode-button.tsx file demonstrates this pattern by conditionally rendering UI elements based on the generationOpen and generationComplete flags.
// components/generation/interactive-mode-button.tsx
const generationOpen = useMediaGenerationStore(state => state.generationOpen);
const generationComplete = useStageStore(state => state.generationComplete);
return (
<>
{generationOpen && !generationComplete && <LoadingSpinner />}
{generationComplete && <LessonViewer />}
</>
);
This subscription model ensures that the interface remains responsive while the server-side pipeline processes complex generation tasks, providing immediate visual feedback when intermediate artifacts arrive.
End-to-End Data Flow
The complete lesson generation pipeline follows a deterministic sequence from prompt to rendered content:
- Prompt → Skill resolver – The user input undergoes parsing in
skill-handle-inference.tsto extract the target skill (e.g.,slide-craft). - Skill → Generation tool –
runGenerationToolinstantiates a job record with a uniquegenerationIdand persists it to the media-generation store. - Tool → Media-generation store – The active tool streams incremental artifacts (outline chunks, generated media URLs) into the Dexie database via
addChunk. - Store → Stage store – Upon receiving the final
generationComplete: truesignal, the orchestrator copies the finalized outline into the stage store. - Stage store → UI – React hooks detect the state change and render the completed lesson slides.
Summary
- The skill parsing layer in
skill-handle-inference.tsextracts tool identifiers from natural language prompts. - The orchestration layer in
generation-tools.tsmanages job lifecycle throughrunGenerationTooland uniquegenerationIdtracking. - Persistent storage relies on Dexie-based
media-generation.tsfor granular progress andstage-store.tsfor completion flags. - The frontend synchronizes via React hooks that subscribe to store changes, enabling real-time progress indicators.
- This architecture provides crash-resilience through IndexedDB persistence and extensibility through the modular tool registry.
Frequently Asked Questions
What triggers the lesson generation pipeline in OpenMAIC?
The pipeline triggers when the skill resolver in lib/server/agent-runtime/skill-handle-inference.ts detects a generation-related command in the user prompt (such as slide-craft or stage-design). This resolver extracts the skill name and invokes runGenerationTool with the appropriate payload, initiating the five-layer orchestration process.
How does OpenMAIC handle crashes during lesson generation?
The system implements crash-resilience through the Dexie-based media-generation store in lib/store/media-generation.ts. Because generation progress persists incrementally to IndexedDB, unfinished jobs retain their state across browser reloads. When the application restarts, the stage store rehydrates from disk, allowing users to resume generation exactly where the process interrupted.
Can I add custom generation tools to the pipeline?
Yes. Developers can extend the pipeline by registering new tools in lib/server/agent-runtime/generation-tools.ts. This requires adding an entry to the generationToolMap dictionary with a unique GenerationToolName and an execution handler that conforms to the runGenerationTool interface. The orchestrator automatically routes matching skill requests to the new implementation without requiring changes to the parsing or persistence layers.
What is the difference between the media-generation store and the stage store?
The media-generation store (lib/store/media-generation.ts) tracks granular, incrementally-updated job data including partial outlines and media URLs during active generation. The stage store (lib/store/stage-store.ts) holds the finalized lesson structure and the generationComplete flag that drives UI state transitions. The media store handles runtime progress while the stage store manages the authoritative lesson presentation state.
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 →