# Generation Contracts and Pipeline Definitions in @openmaic/generation: A Complete Reference

> Explore @openmaic/generation's TypeScript contracts for AI content generation. Learn about retry semantics, result handling, and type-safe data structures for seamless orchestration.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: api-reference
- Published: 2026-09-02

---

**The @openmaic/generation package provides TypeScript contracts for retry semantics, result handling, and type-safe data structures that orchestrate AI-driven content generation in the OpenMAIC framework.**

These generation contracts and pipeline definitions form the foundation for building reliable, extensible AI generation workflows. In [`pipeline-types.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/pipeline-types.ts) and [`generation-retry.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/generation-retry.ts), the OpenMAIC team defines interfaces that decouple your application code from specific LLM implementations while enforcing consistent error handling and data validation.

---

## Generation Contracts: Retry Semantics and Result Handling

Generation contracts control how the system responds to failures, rate limits, and transient errors. They abstract retry logic into reusable, testable primitives.

### GenerationRetryEvent: Observability for Every Attempt

The `GenerationRetryEvent` interface in [`generation-retry.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/generation-retry.ts) exposes metadata for logging, metrics, or UI feedback during retry operations.

```typescript
export interface GenerationRetryEvent {
  label: string;          // Human-readable identifier (e.g. "Slide generation")
  attempt: number;        // Current attempt count (starting at 1)
  maxAttempts: number;    // Total attempts allowed (retries + first try)
  nextDelayMs: number;    // Back-off delay before the next attempt
  reason: string;         // Human-readable cause (e.g. "HTTP 429")
}

```

**Source:** `packages/@openmaic/generation/src/generation-retry.ts` (lines 1-6)

Each field serves a specific purpose. The `attempt` counter helps detect flapping services, while `nextDelayMs` enables progress indicators in user interfaces.

### GenerationRetryOptions: Configurable Retry Behavior

The `GenerationRetryOptions<T>` interface in [`generation-retry.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/generation-retry.ts) accepts a generic type parameter that flows through to the result predicate, enabling type-safe validation of retry-worthy outcomes.

```typescript
export interface GenerationRetryOptions<T> {
  label: string;                     // Identifier shown in logs / events
  maxRetries?: number;               // Maximum retry count (default 5)
  baseDelayMs?: number;              // Initial back-off delay (default 1000 ms)
  maxDelayMs?: number;               // Upper bound for back-off (default 16000 ms)
  signal?: AbortSignal;              // Allows external cancellation
  sleep?: (ms, signal?) => Promise; // Custom sleep implementation (e.g. test mock)
  random?: () => number;             // Custom random source for jitter
  shouldRetryResult?: (result: T) => boolean; // Optional result predicate
  onRetry?: (event: GenerationRetryEvent) => Promise<void> | void;
}

```

**Source:** `packages/@openmaic/generation/src/generation-retry.ts` (lines 9-18)

Key design decisions in this contract:

- **Injectability**: The `sleep` and `random` parameters enable deterministic testing without monkey-patching globals.
- **AbortSignal integration**: Native cancellation support prevents wasted compute when users navigate away or requests time out.
- **Result-based retries**: The `shouldRetryResult` callback handles "successful" HTTP 200 responses with malformed or incomplete AI output.

### GenerationResult: Uniform Output Wrapper

Every pipeline step returns a `GenerationResult<T>` defined in [`pipeline-types.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/pipeline-types.ts), establishing a consistent pattern for success and failure cases.

```typescript
export interface GenerationResult<T> {
  success: boolean;   // `true` when the operation succeeded
  data?: T;            // Payload on success
  error?: string;     // Human-readable error message on failure
}

```

**Source:** `packages/@openmaic/generation/src/pipeline-types.ts` (lines 54-58)

This structure replaces thrown exceptions with explicit error propagation, making control flow predictable and serialization safe for distributed systems.

### Core Helper Functions

Three functions in [`generation-retry.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/generation-retry.ts) implement the retry contract:

- **`withGenerationRetry`** – Executes async operations with exponential back-off, jitter, and abort awareness.
- **`isRetryableGenerationError`** – Classifies errors (network failures, HTTP 5xx, rate limits) as retryable or fatal.
- **`isAbortError`** – Normalizes abort detection across browser `DOMException`, Node `AbortError`, and testing environments.

These exports are available from the package entry point at `packages/@openmaic/generation/src/index.ts`.

---

## Pipeline Definitions: Data Structures for AI Orchestration

Pipeline definitions in [`pipeline-types.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/pipeline-types.ts) describe the information exchanged between your application, the generation pipeline, and underlying AI models.

### AgentInfo: Describing the AI Participant

The `AgentInfo` interface identifies the generative model or service processing your request.

```typescript
export interface AgentInfo {
  id: string;
  name: string;
  role: string;
  persona?: string;
}

```

**Source:** `packages/@openmaic/generation/src/pipeline-types.ts` (lines 7-13)

Use this to tag logs, route requests to specific model endpoints, or apply prompt templates tied to particular personas.

### SceneGenerationContext: Maintaining Cross-Page Coherence

Multi-page presentations require narrative continuity. The `SceneGenerationContext` interface preserves speech patterns and structural awareness across generation calls.

```typescript
export interface SceneGenerationContext {
  pageIndex: number;      // 1-based index of the current page
  totalPages: number;     // Total number of pages in the course
  allTitles: string[];    // Ordered list of all page titles
  previousSpeeches: string[]; // Speech texts from the preceding page only
}

```

**Source:** `packages/@openmaic/generation/src/pipeline-types.ts` (lines 17-23)

The `previousSpeeches` array intentionally includes only the immediate predecessor—this balances context window constraints with voice consistency.

### GeneratedSlideData: Typed Slide Representation

The `GeneratedSlideData` interface defines the contract between AI generation and rendering systems. It enumerates supported visual elements and background specifications.

```typescript
export interface GeneratedSlideData {
  elements: Array<{
    type: 'text' | 'image' | 'video' | 'shape' | 'chart' | 'latex' | 'line';
    left: number;
    top: number;
    width: number;
    height: number;
    [key: string]: unknown;
  }>;
  background?: {
    type: 'solid' | 'gradient';
    color?: string;
    gradient?: {
      type: 'linear' | 'radial';
      colors: Array<{ pos: number; color: string }>;
      rotate: number;
    };
  };
  remark?: string;
}

```

**Source:** `packages/@openmaic/generation/src/pipeline-types.ts` (lines 31-50)

The `[key: string]: unknown` index signature permits extensibility while the `type` discriminant enables exhaustive switch statements in consumers.

### AICallFn: The LLM Abstraction Point

The `AICallFn` type in [`pipeline-types.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/pipeline-types.ts) decouples the pipeline from specific providers. Implement this interface to integrate OpenAI, Anthropic, local models, or mock services.

```typescript
type AICallFn = (
  systemPrompt: string,
  userPrompt: string,
  images?: Array<{ id: string; src: string }>
) => Promise<string>;

```

**Source:** `packages/@openmaic/generation/src/pipeline-types.ts` (lines 60-64)

The `images` parameter supports vision-capable models. The `src` field accepts URLs or base64 data URIs depending on your provider's requirements.

---

## Practical Implementation Patterns

### Implementing Custom Retry Logic with Generation Contracts

This example demonstrates `withGenerationRetry` with result validation and observable retry events.

```typescript
import {
  withGenerationRetry,
  GenerationRetryOptions,
  GenerationResult,
  AICallFn,
} from '@openmaic/generation';

const unstableAICall: AICallFn = async (system, user) => {
  // Simulate rate-limiting behavior
  if (Math.random() < 0.5) {
    throw Object.assign(new Error('Too Many Requests'), { status: 429 });
  }
  return JSON.stringify({ 
    success: true, 
    data: { generatedText: user.toUpperCase() } 
  });
};

const retryConfig: GenerationRetryOptions<GenerationResult<{ generatedText: string }>> = {
  label: 'Text transformation',
  maxRetries: 4,
  baseDelayMs: 500,
  shouldRetryResult: (result) => !result.success || !result.data,
  onRetry: ({ attempt, maxAttempts, reason, nextDelayMs }) => {
    console.log(
      `[${attempt}/${maxAttempts}] Retrying in ${nextDelayMs}ms: ${reason}`
    );
  },
};

async function transformWithRetry(input: string): Promise<string> {
  const result = await withGenerationRetry(
    async () => {
      const raw = await unstableAICall(
        'You are a text transformation service.',
        input
      );
      return JSON.parse(raw) as GenerationResult<{ generatedText: string }>;
    },
    retryConfig
  );
  
  if (!result.success) throw new Error(result.error);
  return result.data!.generatedText;
}

```

The `shouldRetryResult` predicate catches cases where the LLM returns valid JSON with an unsuccessful business logic status—essential for providers that don't surface all failures as HTTP errors.

### Building a Complete Generation Pipeline

This implementation wires together all pipeline definitions into a cohesive workflow.

```typescript
import {
  AgentInfo,
  SceneGenerationContext,
  GeneratedSlideData,
  AICallFn,
  GenerationResult,
  withGenerationRetry,
} from '@openmaic/generation';

// Configure the AI participant
const slideAgent: AgentInfo = {
  id: 'gpt-4-turbo',
  name: 'Slide Designer',
  role: 'presentation_specialist',
  persona: 'expert_educational_content_creator',
};

// Establish narrative context for page 3 of 5
const sceneContext: SceneGenerationContext = {
  pageIndex: 3,
  totalPages: 5,
  allTitles: ['Introduction', 'Core Concepts', 'Implementation', 'Optimization', 'Conclusion'],
  previousSpeeches: ['Welcome to our learning journey.', 'Let us examine the fundamentals.'],
};

// Provider-specific implementation of the contract
const anthropicCaller: AICallFn = async (system, user, images) => {
  const response = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.ANTHROPIC_KEY! },
    body: JSON.stringify({
      model: 'claude-3-opus-20240229',
      system,
      messages: [{ 
        role: 'user', 
        content: images?.length 
          ? [{ type: 'text', text: user }, ...images.map(img => ({
              type: 'image' as const,
              source: { type: 'url' as const, url: img.src }
            }))]
          : user
      }],
      max_tokens: 4096,
    }),
  });
  
  if (!response.ok) throw new Error(`Anthropic error: ${response.status}`);
  const data = await response.json();
  return data.content[0].text;
};

// Retry-wrapped slide generation
async function generateSlideContent(topic: string): Promise<GeneratedSlideData> {
  const result = await withGenerationRetry(
    async () => {
      const rawJSON = await anthropicCaller(
        buildSlideSystemPrompt(slideAgent, sceneContext),
        buildSlideUserPrompt(topic)
      );
      
      // Parse and validate against GenerationResult<GeneratedSlideData>
      return validateSlideResponse(rawJSON);
    },
    {
      label: `Slide generation: ${topic}`,
      maxRetries: 3,
      shouldRetryResult: (r: GenerationResult<GeneratedSlideData>) => !r.success,
    }
  );
  
  if (!result.success) throw new Error(`Slide generation failed: ${result.error}`);
  return result.data!;
}

function buildSlideSystemPrompt(agent: AgentInfo, ctx: SceneGenerationContext): string {
  return `You are ${agent.name}, ${agent.persona}. 
Current page ${ctx.pageIndex} of ${ctx.totalPages}.
Previous narrative: ${ctx.previousSpeeches.join(' → ')}`;
}

function buildSlideUserPrompt(topic: string): string {
  return `Generate a slide for "${topic}" as valid JSON matching the GeneratedSlideData schema.`;
}

function validateSlideResponse(raw: string): GenerationResult<GeneratedSlideData> {
  try {
    const parsed = JSON.parse(raw);
    // Schema validation would occur here
    return { success: true, data: parsed };
  } catch (e) {
    return { success: false, error: `Invalid JSON: ${e.message}` };
  }
}

```

The type system enforces that `GeneratedSlideData` flows through the pipeline, while `GenerationResult` handles both parsing failures and LLM-reported errors without exception throws.

---

## Key Files and Module Structure

| File | Responsibility | Export Pattern |
|------|---------------|--------------|
| [`src/pipeline-types.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/src/pipeline-types.ts) | Pipeline data contracts (`AgentInfo`, `SceneGenerationContext`, `GeneratedSlideData`, `GenerationResult`, `AICallFn`) | Named interfaces and types |
| [`src/generation-retry.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/src/generation-retry.ts) | Retry contracts (`GenerationRetryEvent`, `GenerationRetryOptions`) and execution utilities | `withGenerationRetry`, `isRetryableGenerationError`, `isAbortError` |
| [`src/index.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/src/index.ts) | Public API surface | Re-exports all contracts and generators |

All paths are relative to `packages/@openmaic/generation/`.

---

## Summary

- **Generation contracts** (`GenerationRetryEvent`, `GenerationRetryOptions<T>`, `GenerationResult<T>`) in [`generation-retry.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/generation-retry.ts) provide type-safe retry logic with exponential back-off, jitter, cancellation support, and result-based retry predicates.

- **Pipeline definitions** (`AgentInfo`, `SceneGenerationContext`, `GeneratedSlideData`, `AICallFn`) in [`pipeline-types.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/pipeline-types.ts) establish the data structures for AI orchestration, enabling cross-page coherence and provider abstraction.

- **The `AICallFn` type** decouples your application from specific LLM implementations—swap providers without changing pipeline logic.

- **`withGenerationRetry`** handles transient failures automatically while exposing observability through `GenerationRetryEvent` callbacks.

- All contracts are re-exported from [`src/index.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/src/index.ts) for convenient consumer imports.

---

## Frequently Asked Questions

### What is the difference between generation contracts and pipeline definitions in @openmaic/generation?

**Generation contracts** control execution semantics: how retries behave, what constitutes a failure, and how results are wrapped. They live in [`generation-retry.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/generation-retry.ts). **Pipeline definitions** describe the shape of data moving through your AI workflow—agent descriptions, scene context, and generated output structures. They live in [`pipeline-types.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/pipeline-types.ts). Together they separate "how you call the AI" from "what you send and receive."

### How does withGenerationRetry handle cancellation?

The function accepts an `AbortSignal` through `GenerationRetryOptions.signal`. When triggered, it stops the sleep delay and rejects with an abort error immediately. The `isAbortError` helper normalizes detection across browser, Node.js, and test environments—checking for `DOMException`, `AbortError` names, or signal-rejected promises depending on context.

### Can I use GenerationResult for non-slide generation workflows?

Yes. `GenerationResult<T>` is generic and unconstrained. The OpenMAIC framework uses it for slide generation, but you can apply it to any operation needing consistent success/error discrimination. The interface intentionally avoids slide-specific fields to maximize reusability.

### What happens when shouldRetryResult returns true?

The result predicate in `GenerationRetryOptions` runs after the operation completes successfully. If it returns `true`, the retry cycle continues exactly as for thrown errors—applying exponential back-off, invoking `onRetry` with a `GenerationRetryEvent`, and decrementing the remaining attempt budget. This catches "soft failures" like LLM responses with empty content field or schema validation failures.