@mullion/core
v0.3.0
Published
Core types and utilities for Mullion
Maintainers
Readme
Live Demos
Try Mullion in action (requires Google sign-in, 20 requests/day):
- 🎫 Helpdesk Demo — Scope isolation preventing internal notes from leaking to customers
- 📚 RAG Demo — Fork/merge patterns with role-based access control
Installation
npm install @mullion/coreProject Generator
Scaffold a full Nuxt app with Mullion pre-wired:
npm create mullion@latestNote: create-mullion currently scaffolds Nuxt templates only. Next.js support is planned.
See: https://github.com/mullionlabs/mullion-ts/tree/main/packages/create-mullion
Overview
The core package provides fundamental types and utilities for Mullion's type-safe context management system. Use this package if you want to build custom integrations or don't need the Vercel AI SDK wrapper.
Features
- ✅ Type-safe contexts -
Owned<T, S>with compile-time scope tracking - ✅ Semantic values - Extended outputs with alternatives and reasoning
- ✅ Explicit bridging - Traceable data flow across trust boundaries
- ✅ Fork/merge system - Parallel execution with type-safe aggregation
- ✅ 6 merge strategies - Categorical, continuous, object, array, custom, consensus
- ✅ OpenTelemetry tracing - Zero-dependency OTLP exporter with presets
- ✅ Bridge utilities - Advanced provenance tracking and metadata
- ✅ Zero runtime overhead - Compile-time safety without runtime cost
Key Types
Owned<T, S>
Wraps LLM-generated values with scope tracking and metadata:
import type {Owned} from '@mullion/core';
interface Owned<T, S extends string> {
value: T; // The actual data
confidence: number; // 0-1 confidence score
__scope: S; // Compile-time scope tracking
traceId: string; // Unique identifier for audit trails
}Context<S>
Provides scoped execution environment for LLM operations:
import type {Context} from '@mullion/core';
interface Context<S extends string> {
readonly scope: S;
// Infer structured data from unstructured input
infer<T>(
schema: Schema<T>,
input: string,
options?: InferOptions,
): Promise<Owned<T, S>>;
// Transfer value from another scope
bridge<T, OS extends string>(owned: Owned<T, OS>): Owned<T, S | OS>;
// Extract raw value (scope-safe)
use<T>(owned: Owned<T, S>): T;
}Utilities
createOwned()
Factory function for creating Owned values:
import {createOwned} from '@mullion/core';
const data = createOwned({
value: {name: 'John', age: 30},
scope: 'user-data',
confidence: 0.95,
traceId: 'trace-123',
});
console.log(data.__scope); // 'user-data'isOwned()
Type guard for checking if a value is Owned:
import {isOwned} from '@mullion/core';
if (isOwned(someValue)) {
// TypeScript knows someValue is Owned<unknown, string>
console.log(someValue.confidence);
}Example: Custom Integration
import {createOwned, isOwned} from '@mullion/core';
import type {Context, Owned} from '@mullion/core';
// Create a custom context implementation
class MyContext<S extends string> implements Context<S> {
constructor(public readonly scope: S) {}
async infer<T>(schema: any, input: string): Promise<Owned<T, S>> {
// Your custom LLM integration here
const result = await myLLM.generate(schema, input);
return createOwned({
value: result.data,
scope: this.scope,
confidence: result.confidence,
traceId: `${this.scope}-${Date.now()}`,
});
}
bridge<T, OS extends string>(owned: Owned<T, OS>): Owned<T, S | OS> {
return {
...owned,
__scope: this.scope as S | OS,
};
}
use<T>(owned: Owned<T, S>): T {
if (owned.__scope !== this.scope) {
throw new Error(`Scope mismatch: ${owned.__scope} !== ${this.scope}`);
}
return owned.value;
}
}
// Usage
const ctx = new MyContext('my-scope');
const result = await ctx.infer(schema, 'analyze this text');
if (result.confidence > 0.8) {
console.log('High confidence result:', ctx.use(result));
}SemanticValue
SemanticValue<T, S> extends Owned<T, S> with additional fields for LLM reasoning:
import {createSemanticValue} from '@mullion/core';
import type {SemanticValue, Alternative} from '@mullion/core';
const analysis: SemanticValue<Classification, 'analysis'> = createSemanticValue(
{
value: {category: 'technical', priority: 'high'},
scope: 'analysis',
confidence: 0.85,
traceId: 'trace-456',
reasoning: 'Based on technical keywords and urgency indicators',
alternatives: [
{value: {category: 'support', priority: 'high'}, confidence: 0.75},
{
value: {category: 'technical', priority: 'medium'},
confidence: 0.65,
},
],
},
);
// Access reasoning chain
console.log(analysis.reasoning);
// "Based on technical keywords and urgency indicators"
// Explore alternatives
analysis.alternatives.forEach((alt, i) => {
console.log(
`Alternative ${i + 1}:`,
alt.value,
`(confidence: ${alt.confidence})`,
);
});Use SemanticValue when:
- You need to understand LLM's reasoning process
- Want to provide alternative interpretations to users
- Building systems that require explainability
- Implementing human-in-the-loop workflows with fallbacks
Fork & Merge
Run multiple LLM inferences in parallel with intelligent cache optimization.
Fork Strategies
import {fork} from '@mullion/core';
// Fast parallel: All branches execute immediately
const result = await fork(ctx, {
branches: {
compliance: (c) => c.infer(ComplianceSchema, prompt),
quality: (c) => c.infer(QualitySchema, prompt),
tags: (c) => c.infer(TagsSchema, prompt),
},
strategy: 'fast-parallel',
});
// Cache optimized: Warm up cache first for cost savings
const result = await fork(ctx, {
branches: {
model1: (c) => c.infer(schema, prompt),
model2: (c) => c.infer(schema, prompt),
model3: (c) => c.infer(schema, prompt),
},
strategy: 'cache-optimized',
warmup: 'first-branch',
});Merge Strategies
Aggregate parallel results with 6 built-in strategies:
import {
categorical,
continuous,
object,
array,
custom,
requireConsensus
} from '@mullion/core';
// 1. Categorical weighted vote - for enums/categories
const merged = categorical.weightedVote(results, {
tiebreaker: 'highest-confidence',
});
// 2. Continuous weighted average - for numbers
const merged = continuous.weightedAverage(results, {
field: 'score',
outlierThreshold: 2.0,
});
// 3. Object fieldwise - merge objects field-by-field
const merged = object.fieldwise(results, {
fieldStrategies: {
title: categorical.weightedVote(),
score: continuous.weightedAverage(),
tags: array.concat(),
},
});
// 4. Array concatenation - combine arrays with deduplication
const merged = array.concat(results, {
deduplicate: true,
maxItems: 20,
});
// 5. Custom merge function - your own logic
const merged = custom((values) => ({
value: /* your aggregation */,
confidence: /* your calculation */,
provenance: values.map(v => v.traceId),
}));
// 6. Require consensus - enforce k-of-n agreement
const merged = requireConsensus({
k: 2, // Require 2 out of 3 agreement
baseStrategy: categorical.weightedVote(),
onFailure: 'error',
})(results);Learn more: See docs/reference/fork.md and docs/reference/merge-strategies.md
Bridge Utilities
Advanced bridging utilities for complex dataflow scenarios:
import {
bridgeMultiple,
bridgeWithMetadata,
getProvenance,
isBridged,
} from '@mullion/core';
// Bridge multiple values at once
const [a, b, c] = bridgeMultiple(ctx, [valueA, valueB, valueC]);
// Add custom metadata to bridges
const bridged = bridgeWithMetadata(ctx, value, {
reason: 'Approved for public display',
reviewedBy: 'admin-123',
approvedAt: new Date().toISOString(),
});
// Inspect provenance history
const history = getProvenance(bridged);
console.log(`Value crossed ${history.length} scope boundaries`);
history.forEach((hop, i) => {
console.log(`Hop ${i + 1}: ${hop.fromScope} → ${hop.toScope}`);
console.log(` Reason: ${hop.metadata?.reason}`);
});
// Check if value has been bridged
if (isBridged(value)) {
console.log('This value has crossed scope boundaries');
}Tracing & Observability
Mullion includes production-ready OpenTelemetry-compatible tracing for LLM workflow observability.
Quick Start
import {TracingPresets} from '@mullion/core';
// Enable tracing with one line
TracingPresets.jaeger(); // Local development
// Or for production
TracingPresets.honeycomb(process.env.HONEYCOMB_API_KEY!);Features
- ✅ Zero-dependency OTLP exporter
- ✅ One-liner setup for major backends (Jaeger, Honeycomb, Datadog, New Relic, Grafana)
- ✅ Mullion-specific attributes (scope, confidence, cost, cache metrics)
- ✅ Zero overhead by default (disabled until exporter attached)
- ✅ Full OpenTelemetry compatibility
Manual Instrumentation
import {getGlobalTraceCollector, setupMullionTracing} from '@mullion/core';
setupMullionTracing({
endpoint: 'http://localhost:4318/v1/traces',
});
const collector = getGlobalTraceCollector();
const spanCtx = collector.startSpan({
name: 'mullion.infer',
kind: 'client',
attributes: {
'mullion.scope.id': 'admin',
'mullion.operation': 'infer',
},
});
try {
// Your operation
await performOperation();
await collector.endSpan(spanCtx, {status: 'ok'});
} catch (error) {
await collector.endSpan(spanCtx, {
status: 'error',
statusMessage: error.message,
});
throw error;
}Learn More
See TRACING.md for complete guide including:
- Production setup for all major backends
- Configuration options
- Mullion attribute schema
- Manual instrumentation patterns
- Performance tuning
- Troubleshooting
API Reference
Core Types
Owned<T, S>- Scoped value wrapper with confidence and provenanceSemanticValue<T, S>- Extended Owned with alternatives and reasoningAlternative<T>- Alternative interpretation with confidenceContext<S>- Execution context interfaceSchema<T>- Schema interface (usually Zod)InferOptions- Options for inference operationsBridgeMetadata- Custom metadata for bridge operations
Fork/Merge Types
ForkStrategy- Fork execution strategy ('fast-parallel'|'cache-optimized')WarmupStrategy- Cache warmup strategyForkOptions- Fork configuration optionsForkResult<T>- Fork execution resultsMergeStrategy- Merge strategy typeMergeResult<T>- Merged result with provenanceConflictResolution- How to handle merge conflicts
Tracing Types
MullionSpan- OpenTelemetry-compatible spanSpanContext- Active span contextSpanExporter- Exporter interfaceMullionAttributes- Span attributesMullionOperation- Operation types for tracing
Core Functions
Owned & SemanticValue:
createOwned(params)- Create Owned valueisOwned(value)- Type guard for Owned valuescreateSemanticValue(params)- Create SemanticValueisSemanticValue(value)- Type guard for SemanticValue
Scope:
scope(name, fn)- Create scoped execution context
Bridging:
bridge(ctx, owned)- Bridge value to new scopebridgeSemantic(ctx, semantic)- Bridge SemanticValuebridgeMultiple(ctx, values)- Bridge multiple values at oncebridgeWithMetadata(ctx, value, metadata)- Bridge with custom metadatagetProvenance(value)- Get provenance historyisBridged(value)- Check if value has been bridged
Fork & Merge:
fork(ctx, options)- Execute parallel branchesmerge(results, strategy)- Merge parallel resultsmergeResults(results, strategy)- Convenience wrapper for merge
Merge Strategies:
categorical.weightedVote(options?)- Voting for categorical valuescontinuous.weightedAverage(options?)- Weighted average for numbersobject.fieldwise(options)- Per-field mergingarray.concat(options?)- Array concatenation with deduplicationcustom(fn)- Custom merge functionrequireConsensus(options)- Enforce k-of-n agreement
Tracing:
setupMullionTracing(options)- One-liner tracing setupTracingPresets.jaeger()- Jaeger presetTracingPresets.honeycomb(apiKey)- Honeycomb presetTracingPresets.datadog(apiKey)- Datadog presetTracingPresets.newRelic(key)- New Relic presetTracingPresets.grafana(instanceId, apiKey)- Grafana presetgetGlobalTraceCollector()- Get global collectorsetGlobalTraceCollector(collector)- Set global collectorclearGlobalTraceCollector()- Clear global collectordisableMullionTracing()- Graceful shutdown
Classes
TraceCollector- Span collection and exportOTLPHttpExporter- OTLP/HTTP exporter
Related Packages
- @mullion/ai-sdk - Vercel AI SDK integration with caching and cost tracking
- @mullion/eslint-plugin - Static analysis for context leak prevention
Documentation
- Fork API - Parallel execution patterns
- Merge Strategies - Result aggregation strategies
- Tracing Guide - Complete observability guide
- Examples - Working examples
Contributing
Found a bug or want to contribute? See CONTRIBUTING.md for guidelines.
License
MIT - see LICENSE for details.
