How the PBL v2 System Implements Classroom UI and Project Workflows
The PBL v2 subsystem combines a three-column React workspace shell with orchestrated runtime agents to deliver an interactive Project-Based Learning environment driven by LLM streams and scenario-based roleplay.
The PBL v2 (Project-Based Learning) implementation in the OpenMAIC repository provides a comprehensive classroom interface that manages entire project lifecycles—from initial planning through scenario-based roleplay to final evaluation. This React-based architecture normalizes project state across specialized UI panels while coordinating multiple AI agents to guide learners through structured milestones.
Three-Column Workspace Architecture
The core classroom interface resides in PBLV2Workspace at /components/scene-renderers/pbl/v2/workspace.tsx【/components/scene-renderers/pbl/v2/workspace.tsx#L1-L15】, which initializes a persistent three-column layout that remains mounted throughout the learning session.
The workspace allocates screen real estate as follows:
- Left Sidebar (~22%): Hosts the milestone roadmap and scenario-specific navigation controls, implemented in
/components/scene-renderers/pbl/v2/sidebar.tsx【/components/scene-renderers/pbl/v2/sidebar.tsx#L4-L10】 - Center Agent Chat (~52%): Manages the Instructor LLM thread and learner input interface via
PBLV2Chat【/components/scene-renderers/pbl/v2/chat.tsx#L4-L11】 - Right Submission Panel (~26%): Contains task submission forms, evaluation cards, and scenario briefing tabs【/components/scene-renderers/pbl/v2/submission.tsx#L27-L31】
The shell monitors uiPhase state to determine visibility; when uiPhase is not "workspace", the parent renderer swaps the shell for Hero or Completion screens, though the workspace itself never handles navigation logic【/components/scene-renderers/pbl/v2/workspace.tsx#L8-L11】.
Sidebar Logic and Scenario Support
The sidebar builds a hierarchical tree of milestones and microtasks, automatically marking completed items and expanding the active milestone based on the current project state【/components/scene-renderers/pbl/v2/sidebar.tsx#L6-L9】【/components/scene-renderers/pbl/v2/sidebar.tsx#L33-L40】.
For scenario projects (when project.scenario is true), the sidebar enforces a three-act narrative structure:
- Prep Stage: Displays the Enter scenario button (
enter_scenarioaction) when the learner reaches the preparation milestone【/components/scene-renderers/pbl/v2/sidebar.tsx#L73-L86】 - Role-Play Acts: Shows Complete act (
complete_act) only after the learner sends a message in the simulator thread, preventing premature advancement【/components/scene-renderers/pbl/v2/sidebar.tsx#L86-L97】 - Handover Points: Renders Continue handover (
continue_handover) when a staged transition between milestones is pending【/components/scene-renderers/pbl/v2/sidebar.tsx#L73-L80】
All scene-action buttons respect the sceneBusy state, disabling interaction while server-side task updates are in flight【/components/scene-renderers/pbl/v2/workspace.tsx#L44-L48】.
Chat Interface and Instructor Streaming
The Agent Chat panel connects learner input to the Instructor LLM via the useInstructorStream hook. When a learner submits a message, the system executes a three-step sequence:
- Message Persistence:
appendUserMessageadds the text to the project clone, creates a runtime event, and updates timestamps【/components/scene-renderers/pbl/v2/chat.tsx#L87-L16】 - Stream Initialization: The system POSTs to either
/api/pbl/v2/open-taskfor standard Instructor turns or/api/pbl/v2/evaluatefor evaluation requests, depending on the current microtask status【/components/scene-renderers/pbl/v2/chat.tsx#L81-L87】 - UI Feedback: A "thinking…" indicator displays during
instructorStreamingstates, persisting across Hero-to-Workspace remounts【/components/scene-renderers/pbl/v2/chat.tsx#L69-L76】
The chat interface also enforces handover states—when no active microtask exists (pending handover), the input field disables until the learner clicks the sidebar's Continue button【/components/scene-renderers/pbl/v2/chat.tsx#L88-L92】.
Right-Panel Evaluation and Submission System
The right column dynamically switches between context-aware tabs implemented in /components/scene-renderers/pbl/v2/right-panel-tabs.tsx:
- Scenario Briefing: Available exclusively for scenario projects, displaying narrative context and role information【/components/scene-renderers/pbl/v2/scenario-briefing-gate.tsx】
- Evaluation Cards: Render star ratings and feedback for task, milestone, or project completion via specialized components like
task-evaluation-card.tsx,milestone-card.tsx, andcompletion-cta-card.tsx【/components/scene-renderers/pbl/v2/eval-cards/task-evaluation-card.tsx】
These components consume data from the evaluation pipeline, which generates PBLEvaluation objects after each task submission.
Runtime Agents and Workflow Orchestration
The PBL v2 system coordinates five specialized agents that share a single normalized project instance (normalizeProjectRuntime ensures consistent state across LLM calls)【/lib/pbl/v2/agents/instructor.ts#L41-L44】:
| Agent | Function | Source Location |
|---|---|---|
| Planner | Generates complete PBLProjectV2 structures from outlines, including scenario-specific cast and scene fields【/lib/pbl/v2/agents/planner.ts#L4-L27】 |
lib/pbl/v2/agents/planner.ts |
| Instructor | Builds system prompts containing project context, streams LLM tokens, and processes teaching tools like record_observation and adjust_difficulty |
lib/pbl/v2/agents/instructor.ts |
| Evaluator | Parses evaluation results and creates PBLEvaluation events that populate the right-panel cards |
lib/pbl/v2/agents/evaluator.ts |
| Progress Tracker | Updates microtask completion and applies tier-based difficulty adjustments | lib/pbl/v2/operations/kernel/progress.ts |
| Event Runtime | Manages SSE streaming (PBLProjectPatch) and state transitions via transitionProjectUiPhase |
lib/pbl/v2/operations/kernel/runtime-events.ts |
Project Lifecycle Flow
- Planning:
generatePBLV2Projectcreates the initial structure - Launch:
prepareWorkspaceLaunchProjectsetsuiPhase: 'workspace'and transitions from the Hero screen【/lib/pbl/v2/operations/runtime/workspace-launch.ts#L23-L33】 - Interaction: Learner messages trigger
appendUserMessageandmessage_createdruntime events - Task Completion: The Submit button calls
/api/pbl/v2/task/update, potentially generatingpendingHandoverstates for scenario transitions - Evaluation: The Evaluator agent runs post-submission, storing results as
PBLEvaluationobjects - Persistence:
preparePBLScenesForDocumentPersistencestrips runtime-only data, preserving only the design template for durability【/lib/pbl/v2/runtime/document-persistence.ts#L6-L14】
Technical Implementation Examples
Workspace Shell Component
The following implementation demonstrates the three-panel layout structure:
import { PBLV2Sidebar } from './sidebar';
import { PBLV2AgentTabs } from './agent-tabs';
import { PBLV2SubmissionPanel } from './submission';
import { PBLV2RightPanelTabs } from './right-panel-tabs';
export function PBLV2Workspace({ project, onProjectChange, … }: Props) {
const [panelWidths, setPanelWidths] = useState(DEFAULT_PANEL_WIDTHS);
const activeMilestoneIndex = useMemo(() => workspaceActiveMilestoneIndex(project), [project]);
return (
<div className="flex h-full" style={PBL_WORKSPACE_THEME}>
<PBLV2Sidebar … />
<PBLV2AgentTabs … />
<PBLV2SubmissionPanel … />
<PBLV2RightPanelTabs … />
</div>
);
}
Source: components/scene-renderers/pbl/v2/workspace.tsx【/components/scene-renderers/pbl/v2/workspace.tsx#L1-L15】
Scenario Action Dispatch
The sidebar triggers scene transitions through a centralized action handler:
const runSceneAction = useCallback(
async (action: 'enter_scenario' | 'continue_handover' | 'complete_act') => {
setSceneBusy(true);
const res = await fetch('/api/pbl/v2/task/update', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ project, action }),
});
if (res.ok) {
const { project: nextProject } = await res.json();
onProjectChange(nextProject);
}
setSceneBusy(false);
},
[project, onProjectChange],
);
Source: components/scene-renderers/pbl/v2/workspace.tsx【/components/scene-renderers/pbl/v2/workspace.tsx#L44-L51】
Instructor Streaming Implementation
The Instructor agent handles LLM streaming for educational guidance:
export async function runInstructorTurn(project: PBLProjectV2) {
const system = await loadPBLV2Prompt('instructor-system');
await streamLLM({
model,
system,
prompt: '',
onToken: (t) => setDraftAssistant((s) => s + t),
onFinish: (patch) => applyPatch(patch),
});
}
Conceptual flow derived from PBLV2Chat and lib/pbl/v2/agents/instructor.ts【/components/scene-renderers/pbl/v2/chat.tsx#L61-L69】【/lib/pbl/v2/agents/instructor.ts#L4-L12】
Summary
- The PBLV2Workspace component provides a stable three-column React shell that persists across navigation changes while delegating actual routing to parent renderers.
- Scenario projects enforce narrative structure through the sidebar's action buttons (
enter_scenario,complete_act,continue_handover), which POST to/api/pbl/v2/task/updateand advance milestones only after learner engagement. - The Instructor agent streams LLM responses through the central chat panel, maintaining state via
instructorStreamingflags that survive component remounts. - Project state normalization occurs before every agent turn, ensuring consistent data shapes across Planner, Instructor, and Evaluator operations.
- Document persistence strips runtime-only fields via
preparePBLScenesForDocumentPersistence, storing only the design template for long-term durability.
Frequently Asked Questions
How does the PBL v2 system handle transitions between scenario acts?
The system uses the handover mechanism managed by the sidebar's runSceneAction dispatcher. When a learner completes a role-play act, the complete_act action validates that the learner actually participated in the simulator thread before marking the milestone complete. The continue_handover action then advances to the next milestone (either subsequent role-play acts or the wrap-up stage), with the chat interface disabling input until the learner explicitly clicks Continue【/components/scene-renderers/pbl/v2/sidebar.tsx#L86-L97】【/components/scene-renderers/pbl/v2/chat.tsx#L88-L92】.
What triggers the Instructor agent to stream responses to the learner?
The Instructor agent initiates streaming when the learner submits a message via the chat interface. The appendUserMessage function updates the project state and emits a message_created event, then the system POSTs to /api/pbl/v2/open-task (or /api/pbl/v2/evaluate for evaluation turns). The Instructor builds a system prompt containing the current project, milestone, and microtask context, then streams tokens back to the UI while processing teaching tools like record_observation【/components/scene-renderers/pbl/v2/chat.tsx#L81-L87】【/lib/pbl/v2/agents/instructor.ts#L4-L12】.
How does OpenMAIC persist PBL v2 project state between sessions?
The system uses preparePBLScenesForDocumentPersistence in lib/pbl/v2/runtime/document-persistence.ts to strip transient runtime data—such as streaming states, temporary events, and UI phase flags—before saving. Only the design template and completed milestone structures persist to the document store. When reloading, prepareWorkspaceLaunchProject rehydrates the workspace state and resets uiPhase to "workspace"【/lib/pbl/v2/runtime/document-persistence.ts#L6-L14】【/lib/pbl/v2/operations/runtime/workspace-launch.ts#L23-L33】.
What is the difference between the Planner and Evaluator agents in PBL v2?
The Planner (lib/pbl/v2/agents/planner.ts) operates once at project creation, generating the complete PBLProjectV2 structure from an outline using tool-calling loops, including scenario-specific cast and scene fields【/lib/pbl/v2/agents/planner.ts#L4-L27】. The Evaluator (lib/pbl/v2/agents/evaluator.ts) runs repeatedly after task submissions to assess learner work, create PBLEvaluation objects, and populate the right-panel evaluation cards with feedback and star ratings.
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 →