# How OpenMAIC Implements Defensive Action Filtering to Ensure Scene-Appropriateness

> Discover how OpenMAIC implements defensive action filtering to ensure scene-appropriateness. Learn about its multi-layered pipeline for validating and securing AI-generated scene modifications.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: how-to-guide
- Published: 2026-09-04

---

**OpenMAIC safeguards scene integrity through a multi-layered defensive filtering pipeline in [`lib/workbench/workspace-actions.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-actions.ts) that validates action shapes, enforces scene-ID matching, deduplicates entries, and applies length limits before any AI-generated actions modify the scene graph.**

The THU-MAIC/OpenMAIC repository employs a robust defensive action filtering system to guarantee that only well-formed, scene-appropriate commands reach the course generation engine. This protective layer intercepts raw outputs from AI tools—such as `generate_scene` or `duplicate_scene`—and systematically eliminates malformed, out-of-scope, or excessively large payloads. By centralizing these guardrails in the workbench layer, OpenMAIC prevents scene corruption and ensures deterministic replay of actions across client and server environments.

## The Defensive Action Filtering Pipeline

OpenMAIC processes every batch of `SceneAction` objects through a strict validation sequence before persistence. This pipeline operates within the workspace-actions module to enforce data integrity at the system boundary.

### Action Shape Validation

The system first inspects each incoming action for required structural fields including `id`, `type`, and `sceneId`. Malformed entries lacking these mandatory properties are immediately dropped, preventing invalid JSON from propagating to downstream rendering logic. As implemented in the defensive parsing routines, this step mirrors the protective validation found in [`lib/workbench/session-store.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/session-store.ts) where user-question options are parsed defensively to eliminate malformed pairs.

### Scene-ID Verification

After structural validation, the filter verifies that each action targets an existing scene within the current course context. The system cross-references the `sceneId` property against the active `CourseState` scene list, discarding any actions referencing non-existent or stale identifiers. This defensive matching eliminates stray commands that could otherwise corrupt the scene graph or inject content into unintended course sections.

### Deduplication and Ordering

The pipeline collapses duplicate actions targeting identical scenes to prevent redundant operations, then sorts the remaining entries by their explicit `order` field. This deduplication step guarantees deterministic replay behavior, ensuring that the client and server process scene modifications in a consistent, predictable sequence regardless of AI generation variance.

### Content Length Guardrails

To mitigate hallucination risks from LLM outputs, OpenMAIC applies defensive caps on textual field lengths. In `packages/@openmaic/generation/src/scene-generator.ts`, the generator enforces maximum lengths on fields such as `courseTitle` (lines 77-88) and discards empty strings. These limits prevent excessively large payloads from impacting performance while ensuring meaningful content standards.

### No-Op Fallback Protection

When the filtering pipeline would otherwise remove every action in a batch—indicating a complete generation failure—the system triggers a defensive no-op fallback. As documented in the scene generator source (line 92), this path retains the previous stable scene state rather than propagating an empty or broken action set, protecting the UI from crashing due to unpredictable AI outputs.

## Implementation in the Workbench Layer

The [`lib/workbench/workspace-actions.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-actions.ts) module exposes the public API functions `applySceneActions` and `filterSceneActions`, which serve as the exclusive entry points for scene-modifying operations. These functions wrap the defensive pipeline and return sanitized action lists safe for consumption by the rest of the system.

```typescript
// lib/workbench/workspace-actions.ts
export function applySceneActions(
  actions: SceneAction[],
  course: CourseState,
): SceneAction[] {
  // 1️⃣ Drop malformed entries missing required fields
  const wellFormed = actions.filter(isValidAction);

  // 2️⃣ Keep only actions targeting existing scenes
  const matched = wellFormed.filter(a => 
    course.scenes.some(s => s.id === a.sceneId)
  );

  // 3️⃣ Deduplicate and sort by explicit order
  const unique = dedupeAndSort(matched);

  // 4️⃣ Enforce defensive length caps
  return unique.map(capLengths);
}

```

When invoking generation tools, developers pass raw LLM outputs through this filter before applying state changes:

```typescript
// Example: Defensive filtering before scene state update
import { runTool } from '@/lib/server/agent-runtime';
import { applySceneActions } from '@/lib/workbench/workspace-actions';

const rawResult = await runTool('generate_scene', { 
  instruction: 'Add a summary slide' 
});

// Raw actions from the LLM are sanitized before application
const safeActions = applySceneActions(rawResult.actions, currentCourseState);

```

## Key Source Files

The defensive action filtering system spans several critical modules within the OpenMAIC architecture:

- **[`lib/workbench/workspace-actions.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-actions.ts)** — Central hub implementing `applySceneActions` and `filterSceneActions`; coordinates the multi-stage validation pipeline.

- **`packages/@openmaic/generation/src/scene-generator.ts`** — Contains defensive no-op fallback logic (line 92) and length validation guardrails for generated text fields (lines 77-88).

- **[`lib/workbench/session-store.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/session-store.ts)** — Demonstrates defensive parsing patterns for user options (line 784), informing the action validation approach used upstream.

- **[`lib/pbl/v2/agents/instructor.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/pbl/v2/agents/instructor.ts)** — Implements defensive handling of role-play actions to ensure simulator ownership of scene state transitions (line 793).

## Summary

- OpenMAIC validates every `SceneAction` for required fields (`id`, `type`, `sceneId`) before processing, dropping malformed entries immediately.
- Scene-ID matching ensures actions target only existing scenes within the current course context, preventing graph corruption.
- Deduplication and explicit ordering guarantee deterministic replay across distributed client-server environments.
- Defensive length caps and empty-string checks in the generation layer mitigate LLM hallucination risks.
- A no-op fallback mechanism preserves stable scene states when AI generation produces exclusively invalid actions.
- All filtering logic is centralized in [`lib/workbench/workspace-actions.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-actions.ts) to maintain consistent security boundaries.

## Frequently Asked Questions

### What is defensive action filtering in OpenMAIC?

Defensive action filtering is a protective preprocessing step that intercepts AI-generated scene modifications before they reach the persistence layer. The system validates action structures, verifies target scene existence, and enforces content constraints to ensure only appropriate, well-formed commands alter the course state.

### How does OpenMAIC prevent malformed actions from reaching the scene graph?

The `applySceneActions` function in [`lib/workbench/workspace-actions.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-actions.ts) inspects each action for mandatory properties and structural integrity. Actions failing validation—such as those missing `sceneId` or `type` fields—are filtered out before the batch proceeds to deduplication or state application, effectively isolating the scene graph from corrupted data.

### What happens when all actions fail validation?

When the defensive pipeline would eliminate every action in a batch—indicating a complete generation failure—the system invokes a no-op fallback path. As implemented in `packages/@openmaic/generation/src/scene-generator.ts`, this fallback retains the previous stable scene state rather than applying an empty action set, ensuring UI stability and preventing crash scenarios.

### Where is the filtering logic centralized in the codebase?

All defensive filtering logic is centralized in the **workspace-actions** module at [`lib/workbench/workspace-actions.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/workbench/workspace-actions.ts). This module exports the primary `applySceneActions` and `filterSceneActions` functions, which serve as the mandatory entry points for any tool or agent attempting to modify scene state, ensuring consistent enforcement of appropriateness rules across the entire application.