Composition Patterns
Rotifer provides a formal gene algebra for composing simple genes into complex behaviors. This is one of the key differentiators from traditional skill/tool systems — compositions are type-safe, verifiable, and automatically optimizable.
Composition Operators
Section titled “Composition Operators”Seq — Sequential Execution
Section titled “Seq — Sequential Execution”Execute genes one after another, piping the output of each gene as input to the next.
Seq(A, B, C) = A → B → Cimport { Seq } from "@rotifer/algebra";
const pipeline = Seq( "genesis-web-search", // Step 1: Search the web "text-summarize", // Step 2: Summarize results "text-translate" // Step 3: Translate summary);
// Input flows: search → summarize → translateconst result = await pipeline.execute({ query: "quantum computing breakthroughs"});Data flow: Output of gene N becomes input of gene N+1. Schemas must be compatible (output of A must satisfy input of B).
Par — Parallel Execution
Section titled “Par — Parallel Execution”Execute genes concurrently and collect all results. Uses true CPU parallelism via thread pool.
Par(A, B, C) = A ‖ B ‖ C → [resultA, resultB, resultC]import { Par } from "@rotifer/algebra";
const multiSearch = Par( "genesis-web-search", // Search provider 1 "genesis-web-search-lite", // Search provider 2 "academic-search" // Academic sources);
// All three run simultaneouslyconst results = await multiSearch.execute({ query: "rotifer protocol"});// results = [searchResult1, searchResult2, academicResult]Use cases:
- Fan-out queries to multiple data sources
- Redundant execution for fault tolerance
- Independent subtask parallelism
Cond — Conditional Branching
Section titled “Cond — Conditional Branching”Choose which gene to execute based on a runtime predicate.
Cond(predicate, thenGene, elseGene)import { Cond } from "@rotifer/algebra";
const smartSearch = Cond( (input) => input.query.length > 100, // Long query? "deep-research-gene", // Yes: deep research "genesis-web-search" // No: quick search);Use cases:
- Route requests based on input characteristics
- A/B testing between gene implementations
- Graceful degradation based on resource availability
Try — Error Recovery
Section titled “Try — Error Recovery”Execute a primary gene; if it fails, fall back to a secondary gene.
Try(primary, fallback) = primary ?? fallbackimport { Try } from "@rotifer/algebra";
const resilientSearch = Try( "premium-api-search", // Try premium API first "genesis-web-search" // Fall back to free search);Behavior:
- If primary succeeds → return primary result
- If primary throws → execute fallback, return fallback result
- If both fail → propagate the fallback error
Transform — Data Transformation
Section titled “Transform — Data Transformation”Apply a transformation function between genes to reshape data.
Transform(gene, mapFn) = gene → mapFn(result)import { Transform, Seq } from "@rotifer/algebra";
const pipeline = Seq( "genesis-web-search", Transform((searchResult) => ({ text: searchResult.results.map(r => r.snippet).join("\n"), maxLength: 200 })), "text-summarize");Composition Patterns
Section titled “Composition Patterns”Pattern 1: Search → Summarize → Translate Pipeline
Section titled “Pattern 1: Search → Summarize → Translate Pipeline”const researchPipeline = Seq( "genesis-web-search", Transform((r) => ({ text: r.results[0].snippet })), "text-summarize", Transform((r) => ({ text: r.summary, targetLang: "zh" })), "text-translate");Pattern 2: Parallel Search with Aggregation
Section titled “Pattern 2: Parallel Search with Aggregation”const multiSourceSearch = Seq( Par( "web-search", "academic-search", "code-search" ), Transform((results) => ({ text: results.flat().map(r => r.title).join(", ") })), "text-summarize");Pattern 3: Resilient Pipeline with Fallbacks
Section titled “Pattern 3: Resilient Pipeline with Fallbacks”const robustPipeline = Seq( Try("premium-search", "free-search"), Try("gpt4-summarize", "local-summarize"), "text-translate");Pattern 4: Conditional Processing
Section titled “Pattern 4: Conditional Processing”const adaptivePipeline = Seq( "genesis-web-search", Cond( (r) => r.results.length > 10, "deep-analysis-gene", // Many results: analyze deeply "quick-summary-gene" // Few results: quick summary ));Type Safety
Section titled “Type Safety”The composition algebra enforces type compatibility at composition time:
Seq(A, B)requiresA.outputSchema ⊇ B.inputSchemaPar(A, B)requiresA.inputSchema = B.inputSchemaCond(p, T, F)requiresT.outputSchema = F.outputSchemaTry(P, F)requiresP.outputSchema = F.outputSchema
Incompatible compositions produce compile-time errors:
Error[E0032]: Type mismatch in Seq composition → gene 'web-search' output: { results: SearchResult[] } → gene 'translate' input: { text: string, targetLang: string }
help: Add a Transform between the genes to reshape the dataFitness Implications
Section titled “Fitness Implications”Composed genes inherit fitness from their components:
- Seq — F(Seq) = min(F(components)) × latency_penalty
- Par — F(Par) = avg(F(components)) × parallelism_bonus
- Try — F(Try) = F(primary) × success_rate + F(fallback) × (1 - success_rate)
The Arena evaluates compositions as a whole, creating selection pressure for efficient composition structures.