Type Reference
Complete TypeScript interfaces and types used throughout dag-engine.
Table of Contents
- Section & Result Types
- Context Types
- Provider Types
- Cost Types
- Progress Types
- Dimension Types
- Error & Skip Types
- Type Guards
- Quick Reference
Section & Result Types
SectionData
Input unit for processing. Each section represents one item to analyze.
interface SectionData {
content: string; // Text to analyze
metadata: Record<string, unknown>; // Additional data
}Example:
const section: SectionData = {
content: 'Great product! Highly recommend.',
metadata: {
id: 'review-123',
userId: 456,
productId: 'SKU-789',
timestamp: '2024-01-15',
rating: 5
}
};Usage:
const sections: SectionData[] = [
{ content: 'Review 1', metadata: { id: 1 } },
{ content: 'Review 2', metadata: { id: 2 } },
{ content: 'Review 3', metadata: { id: 3 } }
];
const result = await engine.process(sections);DimensionResult
Result from a dimension execution. Contains data, error, or skip information.
interface DimensionResult<T = unknown> {
data?: T; // Successful result data
error?: string; // Error message if failed
metadata?: ProviderMetadata; // Execution metadata
}Examples:
Success:
const result: DimensionResult<SentimentData> = {
data: {
sentiment: 'positive',
score: 0.95,
reasoning: 'Enthusiastic language with superlatives'
},
metadata: {
provider: 'anthropic',
model: 'claude-3-5-haiku-20241022',
tokens: {
inputTokens: 45,
outputTokens: 12,
totalTokens: 57
},
cost: 0.0001,
cached: false,
skipped: false
}
};Error:
const result: DimensionResult = {
error: 'Rate limit exceeded',
metadata: {
provider: 'anthropic',
skipped: false
}
};Skipped:
const result: DimensionResult = {
metadata: {
skipped: true,
reason: 'Spam detected'
}
};ProcessResult
Final result returned from engine.process().
interface ProcessResult {
sections: Array<{
section: SectionData;
results: Record<string, DimensionResult>;
}>;
globalResults: Record<string, DimensionResult>;
transformedSections: SectionData[];
costs?: CostSummary;
metadata?: unknown;
}Example:
const result: ProcessResult = await engine.process(sections);
// Access section results
result.sections.forEach((sectionResult) => {
console.log('Section:', sectionResult.section.content);
const sentiment = sectionResult.results.sentiment?.data;
console.log('Sentiment:', sentiment.sentiment);
const topics = sectionResult.results.topics?.data;
console.log('Topics:', topics.topics);
});
// Access global results
const summary = result.globalResults.overall_summary?.data;
console.log('Summary:', summary.text);
// Access costs
console.log('Total cost:', result.costs?.totalCost);
console.log('Total tokens:', result.costs?.totalTokens);
// Access transformed sections (if transformations occurred)
console.log('Final sections:', result.transformedSections.length);DimensionDependencies
Dependencies passed to dimensions. Map of dimension name to its result.
interface DimensionDependencies {
[dimensionName: string]: DimensionResult;
}Example:
// In createPrompt()
createPrompt(context: PromptContext) {
const dependencies: DimensionDependencies = context.dependencies;
// Access dependency results
const sentiment = dependencies.sentiment?.data;
const topics = dependencies.topics?.data;
if (context.dimension === 'summary') {
return `Create a ${sentiment.sentiment} summary covering: ${topics.topics.join(', ')}
Content: "${context.sections[0].content}"`;
}
}Structure for Section Dimensions:
// Each section gets its own dependency results
const dependencies: DimensionDependencies = {
sentiment: {
data: { sentiment: 'positive', score: 0.95 },
metadata: { ... }
},
topics: {
data: { topics: ['quality', 'price'] },
metadata: { ... }
}
};Structure for Global Dimensions:
// Global dimensions get aggregated results
const dependencies: DimensionDependencies = {
sentiment: {
data: {
sections: [
{ data: { sentiment: 'positive', score: 0.95 } },
{ data: { sentiment: 'negative', score: 0.2 } },
{ data: { sentiment: 'neutral', score: 0.5 } }
],
aggregated: true,
totalSections: 3
},
metadata: { ... }
}
};Context Types
BaseContext
Base fields present in all contexts.
interface BaseContext {
processId: string; // Unique process ID (UUID v4)
timestamp: number; // Context creation time (ms since epoch)
}PromptContext
Context passed to createPrompt() method. Used to build prompts for AI providers.
interface PromptContext {
sections: SectionData[]; // Sections to process
dimension: string; // Current dimension name
dependencies: DimensionDependencies; // Results from dependencies
isGlobal: boolean; // false for section, true for global
}Example:
createPrompt(context: PromptContext): string {
const { dimension, sections, dependencies, isGlobal } = context;
if (dimension === 'sentiment') {
return `Analyze the sentiment of this review:
"${sections[0].content}"
Respond with JSON: { "sentiment": "positive" | "negative" | "neutral", "score": 0-1 }`;
}
if (dimension === 'summary' && isGlobal) {
const sentiments = dependencies.sentiment?.data?.sections || [];
return `Create a summary of ${sentiments.length} reviews...`;
}
return `Analyze: ${sections[0].content}`;
}ProcessContext
Context for process-level hooks (defineDependencies, etc.).
interface ProcessContext extends BaseContext {
sections: SectionData[];
options: ProcessOptions;
metadata?: unknown; // From beforeProcessStart
}BeforeProcessStartContext
Context for beforeProcessStart hook.
interface BeforeProcessStartContext extends BaseContext {
sections: SectionData[]; // Input sections
options: ProcessOptions; // Process options
}Example:
async beforeProcessStart(
context: BeforeProcessStartContext
): Promise<ProcessStartResult> {
console.log(`Starting process ${context.processId}`);
console.log(`Processing ${context.sections.length} sections`);
// Filter out empty sections
const filteredSections = context.sections.filter(
s => s.content.trim().length > 0
);
return {
sections: filteredSections,
metadata: { originalCount: context.sections.length }
};
}ProcessStartResult
Return type for beforeProcessStart hook.
interface ProcessStartResult {
sections?: SectionData[]; // Modified sections
metadata?: unknown; // Custom metadata
}Example:
// Return modified sections
return {
sections: filteredSections,
metadata: { timestamp: Date.now() }
};
// Return just metadata
return {
metadata: { environment: 'production' }
};
// Return nothing (no changes)
return undefined;ProcessResultContext
Context for afterProcessComplete hook.
interface ProcessResultContext extends ProcessContext {
result: ProcessResult; // Complete results
duration: number; // Total duration (ms)
totalDimensions: number; // Total dimensions executed
successfulDimensions: number; // Successful dimensions
failedDimensions: number; // Failed dimensions
}Example:
async afterProcessComplete(
context: ProcessResultContext
): Promise<ProcessResult> {
console.log(`Process completed in ${context.duration}ms`);
console.log(`Success: ${context.successfulDimensions}/${context.totalDimensions}`);
// Add custom metadata to result
return {
...context.result,
metadata: {
...context.result.metadata,
duration: context.duration,
successRate: context.successfulDimensions / context.totalDimensions
}
};
}ProcessFailureContext
Context for handleProcessFailure hook.
interface ProcessFailureContext extends ProcessContext {
error: Error; // The error that caused failure
partialResults: Partial<ProcessResult>; // Results completed before failure
duration: number; // Duration until failure (ms)
}Example:
async handleProcessFailure(
context: ProcessFailureContext
): Promise<ProcessResult | void> {
console.error(`Process failed after ${context.duration}ms`);
console.error(`Error: ${context.error.message}`);
// Return partial results
return {
sections: context.partialResults.sections || [],
globalResults: context.partialResults.globalResults || {},
transformedSections: context.partialResults.transformedSections || [],
metadata: {
failed: true,
error: context.error.message
}
};
}DimensionContext
Context for dimension-level hooks.
interface DimensionContext extends BaseContext {
dimension: string; // Current dimension name
isGlobal: boolean; // false for section, true for global
sections: SectionData[]; // All sections
dependencies: DimensionDependencies; // Results from dependencies
globalResults: Record<string, DimensionResult>; // Previous global results
}Used by:
shouldSkipGlobalDimensiontransformDependenciesbeforeDimensionExecute
Example:
async shouldSkipGlobalDimension(
context: DimensionContext
): Promise<boolean> {
// Skip if no sections
if (context.sections.length === 0) {
return true;
}
// Skip if dependency failed
const required = context.dependencies.required_data;
if (required?.error) {
return true;
}
return false;
}SectionDimensionContext
Context for section dimension hooks (extends DimensionContext).
interface SectionDimensionContext extends DimensionContext {
section: SectionData; // Current section being processed
sectionIndex: number; // Index of current section (0-based)
}Used by:
shouldSkipSectionDimension
Example:
async shouldSkipSectionDimension(
context: SectionDimensionContext
): Promise<boolean | SkipWithResult> {
console.log(`Processing section ${context.sectionIndex}`);
console.log(`Section content: ${context.section.content}`);
// Skip based on section content
if (context.section.content.length < 50) {
return true;
}
// Skip based on dependency
const spamCheck = context.dependencies.spam_check;
if (spamCheck?.data?.is_spam === true) {
return true;
}
// Return cached result
const cached = await redis.get(`${context.dimension}:${context.sectionIndex}`);
if (cached) {
return {
skip: true,
result: {
data: JSON.parse(cached),
metadata: { cached: true }
}
};
}
return false;
}ProviderContext
Context for provider-level hooks (beforeProviderExecute).
interface ProviderContext extends DimensionContext {
request: ProviderRequest; // The request to be sent
provider: string; // Provider name (e.g., 'anthropic')
providerOptions: Record<string, unknown>; // Provider options
}Example:
async beforeProviderExecute(
context: ProviderContext
): Promise<ProviderRequest> {
console.log(`Executing ${context.dimension} with ${context.provider}`);
// Log request
console.log('Request:', context.request.input);
// Modify request
return {
...context.request,
options: {
...context.request.options,
temperature: 0.2 // Override temperature
}
};
}ProviderResultContext
Context for afterProviderExecute hook.
interface ProviderResultContext extends ProviderContext {
result: ProviderResponse; // The response received
duration: number; // Request duration (ms)
tokensUsed?: TokenUsage; // Token usage
}Example:
async afterProviderExecute(
context: ProviderResultContext
): Promise<ProviderResponse> {
console.log(`${context.provider} responded in ${context.duration}ms`);
console.log(`Tokens used: ${context.tokensUsed?.totalTokens}`);
// Validate response
if (!context.result.data) {
return {
error: 'Empty response from provider',
metadata: context.result.metadata
};
}
return context.result;
}DimensionResultContext
Context for afterDimensionExecute hook.
interface DimensionResultContext extends BaseContext {
dimension: string;
isGlobal: boolean;
sections: SectionData[];
dependencies: DimensionDependencies;
globalResults: Record<string, DimensionResult>;
section?: SectionData; // Present for section dimensions
sectionIndex?: number; // Present for section dimensions
result: DimensionResult; // The result just produced
duration: number; // Execution time (ms)
provider: string; // Provider used
model?: string; // Model used
tokensUsed?: TokenUsage; // Token usage
cost?: number; // Cost incurred
}Example:
async afterDimensionExecute(
context: DimensionResultContext
): Promise<void> {
const type = context.isGlobal ? 'global' : `section ${context.sectionIndex}`;
console.log(`${context.dimension} (${type}) completed in ${context.duration}ms`);
if (context.tokensUsed) {
console.log(`Tokens: ${context.tokensUsed.totalTokens}`);
console.log(`Cost: $${context.cost?.toFixed(4)}`);
}
// Log to analytics
await analytics.track('dimension_complete', {
dimension: context.dimension,
duration: context.duration,
tokens: context.tokensUsed?.totalTokens
});
}TransformSectionsContext
Context for transformSections hook (extends ProviderResultContext).
interface TransformSectionsContext extends ProviderResultContext {
currentSections: SectionData[]; // Current sections before transformation
}Example:
async transformSections(
context: TransformSectionsContext
): Promise<SectionData[] | undefined> {
if (context.dimension !== 'group_by_category') {
return undefined; // No transformation
}
const groups = context.result.data?.groups || [];
// Transform: 100 sections → 5 category groups
return groups.map(group => ({
content: group.reviews.join('\n\n'),
metadata: {
category: group.category,
count: group.reviews.length,
originalSections: group.indices
}
}));
}FinalizeContext
Context for finalizeResults hook.
interface FinalizeContext extends BaseContext {
results: Record<string, DimensionResult>; // All dimension results
originalSections: SectionData[]; // Original input sections
currentSections: SectionData[]; // Current sections (post-transform)
globalResults: Record<string, DimensionResult>; // Global results
duration: number; // Total process duration (ms)
}Example:
async finalizeResults(
context: FinalizeContext
): Promise<Record<string, DimensionResult>> {
console.log(`Finalizing ${Object.keys(context.results).length} results`);
console.log(`Process took ${context.duration}ms`);
// Add summary statistics
const modifiedResults = { ...context.results };
modifiedResults['_summary'] = {
data: {
totalDimensions: Object.keys(context.results).length,
totalSections: context.originalSections.length,
finalSections: context.currentSections.length,
duration: context.duration
}
};
return modifiedResults;
}Provider Types
ProviderRequest
Request sent to AI provider.
interface ProviderRequest {
input: string | string[]; // Prompt(s)
options?: Record<string, unknown>; // Model, temperature, etc.
dimension?: string; // Dimension name
isGlobal?: boolean; // Global or section dimension
metadata?: {
sectionIndex?: number; // Section index (for section dims)
totalSections?: number; // Total sections in process
[key: string]: unknown;
};
}Example:
const request: ProviderRequest = {
input: 'Analyze sentiment of: "Great product!"',
options: {
model: 'claude-3-5-haiku-20241022',
temperature: 0.2,
max_tokens: 1000
},
dimension: 'sentiment',
isGlobal: false,
metadata: {
sectionIndex: 0,
totalSections: 10
}
};ProviderResponse
Response from AI provider.
interface ProviderResponse<T = unknown> {
data?: T; // Parsed response data
error?: string; // Error message if failed
metadata?: ProviderMetadata; // Execution metadata
}Example:
const response: ProviderResponse<SentimentData> = {
data: {
sentiment: 'positive',
score: 0.95
},
metadata: {
provider: 'anthropic',
model: 'claude-3-5-haiku-20241022',
tokens: {
inputTokens: 45,
outputTokens: 12,
totalTokens: 57
},
cost: 0.0001
}
};ProviderMetadata
Metadata about execution.
interface ProviderMetadata {
model?: string; // Model used
tokens?: TokenUsage; // Token usage
provider?: string; // Provider name
cost?: number; // Cost incurred
cached?: boolean; // Whether result was cached
skipped?: boolean; // Whether dimension was skipped
reason?: string; // Skip reason (if skipped)
[key: string]: unknown; // Custom metadata
}Example:
const metadata: ProviderMetadata = {
provider: 'anthropic',
model: 'claude-3-7-sonnet-20250219',
tokens: {
inputTokens: 1000,
outputTokens: 500,
totalTokens: 1500
},
cost: 0.0105,
cached: false,
skipped: false,
duration: 2500, // Custom: request duration
requestId: 'req-123', // Custom: provider request ID
retries: 0 // Custom: number of retries
};TokenUsage
Token usage information.
interface TokenUsage {
inputTokens: number;
outputTokens: number;
totalTokens: number;
}Example:
const tokens: TokenUsage = {
inputTokens: 1000,
outputTokens: 500,
totalTokens: 1500
};
// Calculate cost
const cost =
(tokens.inputTokens / 1_000_000) * pricing.inputPer1M +
(tokens.outputTokens / 1_000_000) * pricing.outputPer1M;ProviderSelection
Provider selection returned by selectProvider.
interface ProviderSelection {
provider: string; // Primary provider name
options: Record<string, unknown>; // Provider options
fallbacks?: Array<{ // Fallback providers
provider: string;
options: Record<string, unknown>;
retryAfter?: number; // Delay before trying (ms)
}>;
}Example:
selectProvider(dimension: string): ProviderSelection {
return {
provider: 'anthropic',
options: {
model: 'claude-3-7-sonnet-20250219',
temperature: 0.3,
max_tokens: 2000
},
fallbacks: [
{
provider: 'openai',
options: {
model: 'gpt-4o',
temperature: 0.3
},
retryAfter: 1000 // Wait 1s before trying fallback
},
{
provider: 'gemini',
options: {
model: 'gemini-2.5-pro',
temperature: 0.3
}
}
]
};
}Cost Types
CostSummary
Cost breakdown for entire process.
interface CostSummary {
totalCost: number; // Total cost (USD)
totalTokens: number; // Total tokens used
byDimension: Record<string, DimensionCost>; // Cost per dimension
byProvider: Record<string, { // Cost per provider
cost: number;
tokens: TokenUsage;
models: string[];
}>;
currency: 'USD';
}Example:
const costs: CostSummary = {
totalCost: 0.0282,
totalTokens: 12289,
byDimension: {
filter_spam: {
cost: 0.0115,
tokens: { inputTokens: 6548, outputTokens: 1559, totalTokens: 8107 },
model: 'claude-3-5-haiku-20241022',
provider: 'anthropic'
},
sentiment: {
cost: 0.0015,
tokens: { inputTokens: 704, outputTokens: 230, totalTokens: 934 },
model: 'claude-3-5-haiku-20241022',
provider: 'anthropic'
},
analyze_category: {
cost: 0.0087,
tokens: { inputTokens: 621, outputTokens: 459, totalTokens: 1080 },
model: 'claude-3-7-sonnet-20250219',
provider: 'anthropic'
}
},
byProvider: {
anthropic: {
cost: 0.0282,
tokens: { inputTokens: 7873, outputTokens: 4416, totalTokens: 12289 },
models: ['claude-3-5-haiku-20241022', 'claude-3-7-sonnet-20250219']
}
},
currency: 'USD'
};
console.log(`Total: $${costs.totalCost.toFixed(4)}`);
console.log(`Haiku: $${costs.byDimension.sentiment.cost.toFixed(4)}`);
console.log(`Sonnet: $${costs.byDimension.analyze_category.cost.toFixed(4)}`);DimensionCost
Cost for a single dimension.
interface DimensionCost {
cost: number; // Cost in USD
tokens: TokenUsage; // Token usage
model: string; // Model used
provider: string; // Provider used
}Example:
const dimensionCost: DimensionCost = {
cost: 0.0115,
tokens: {
inputTokens: 6548,
outputTokens: 1559,
totalTokens: 8107
},
model: 'claude-3-5-haiku-20241022',
provider: 'anthropic'
};PricingConfig
Pricing configuration for cost tracking.
interface PricingConfig {
models: Record<string, ModelPricing>; // Model pricing rates
lastUpdated?: string; // Last update date
}
interface ModelPricing {
inputPer1M: number; // Cost per 1M input tokens (USD)
outputPer1M: number; // Cost per 1M output tokens (USD)
}Example:
const pricing: PricingConfig = {
models: {
'claude-3-5-haiku-20241022': {
inputPer1M: 0.80,
outputPer1M: 4.00
},
'claude-3-7-sonnet-20250219': {
inputPer1M: 3.00,
outputPer1M: 15.00
},
'gpt-4o': {
inputPer1M: 2.50,
outputPer1M: 10.00
}
},
lastUpdated: '2024-01-15'
};
// Use in engine config
const engine = new DagEngine({
plugin: myPlugin,
providers: myAdapter,
pricing
});Progress Types
ProgressUpdate
Real-time progress information.
interface ProgressUpdate {
completed: number; // Completed operations
total: number; // Total operations
percent: number; // Completion percentage
cost: number; // Cost so far (USD)
estimatedCost: number; // Estimated total cost (USD)
elapsedSeconds: number; // Time elapsed (seconds)
etaSeconds: number; // Estimated time remaining (seconds)
currentDimension: string; // Current dimension name
currentSection: number; // Current section index
dimensions: { // Per-dimension progress
[dimension: string]: {
completed: number;
total: number;
percent: number;
cost: number;
estimatedCost: number;
failed: number;
etaSeconds: number;
};
};
}Example:
// In process options
const result = await engine.process(sections, {
onProgress: (progress: ProgressUpdate) => {
console.log(`Progress: ${progress.percent.toFixed(1)}%`);
console.log(`Cost so far: $${progress.cost.toFixed(4)}`);
console.log(`Estimated total: $${progress.estimatedCost.toFixed(4)}`);
console.log(`ETA: ${progress.etaSeconds}s`);
console.log(`Current: ${progress.currentDimension}`);
// Per-dimension progress
Object.entries(progress.dimensions).forEach(([dim, stats]) => {
console.log(` ${dim}: ${stats.percent.toFixed(1)}% ($${stats.cost.toFixed(4)})`);
});
}
});
// Or poll for progress
const progress = engine.getProgress();
if (progress) {
console.log(`${progress.completed}/${progress.total} completed`);
}ProgressDisplayOptions
Options for built-in progress display.
interface ProgressDisplayOptions {
display?: "simple" | "bar" | "multi" | "none"; // Display style
format?: string; // Custom format string
showDimensions?: boolean; // Show dimension info
throttleMs?: number; // Update throttle (ms)
}Example:
// Simple text progress
const engine = new DagEngine({
plugin: myPlugin,
providers: myAdapter,
progressDisplay: {
display: 'simple'
}
});
// Progress bar (requires cli-progress)
const engine = new DagEngine({
plugin: myPlugin,
providers: myAdapter,
progressDisplay: {
display: 'bar',
format: 'Progress |{bar}| {percentage}% | ${cost} | ETA: {eta}s'
}
});
// Multiple bars per dimension
const engine = new DagEngine({
plugin: myPlugin,
providers: myAdapter,
progressDisplay: {
display: 'multi',
showDimensions: true,
throttleMs: 100
}
});
// Disable display (use onProgress callback instead)
const engine = new DagEngine({
plugin: myPlugin,
providers: myAdapter,
progressDisplay: false
});Dimension Types
Dimension
Dimension definition (string or config object).
type Dimension = string | DimensionConfig;Examples:
// String form (section dimension)
this.dimensions = ['sentiment', 'topics', 'category'];
// Config form (global dimension)
this.dimensions = [
'sentiment', // section
{ name: 'summary', scope: 'global' } // global
];
// Mixed
this.dimensions = [
'sentiment',
'topics',
{ name: 'overall', scope: 'global' },
{ name: 'categorize', scope: 'global' }
];DimensionConfig
Dimension configuration object.
interface DimensionConfig {
name: string; // Dimension name
scope: 'section' | 'global'; // Execution scope
transform?: ( // Optional transform function
result: DimensionResult,
sections: SectionData[]
) => SectionData[] | Promise<SectionData[]>;
}Examples:
Simple global dimension:
const dimension: DimensionConfig = {
name: 'categorize',
scope: 'global'
};With transform function:
const dimension: DimensionConfig = {
name: 'group_by_category',
scope: 'global',
transform: (result, sections) => {
const groups = result.data?.groups || [];
// Transform: 100 sections → 5 category groups
return groups.map(group => ({
content: group.items.join('\n'),
metadata: {
category: group.name,
count: group.items.length
}
}));
}
};Async transform:
const dimension: DimensionConfig = {
name: 'enrich',
scope: 'global',
transform: async (result, sections) => {
const enrichedData = await api.enrichData(sections);
return sections.map((section, i) => ({
...section,
metadata: {
...section.metadata,
enrichment: enrichedData[i]
}
}));
}
};Filter transform:
const dimension: DimensionConfig = {
name: 'filter_spam',
scope: 'global',
transform: (result, sections) => {
const spamIndices = result.data?.spam_indices || [];
// Filter out spam sections
return sections.filter((_, i) => !spamIndices.includes(i));
}
};Process Options
ProcessOptions
Options passed to engine.process().
interface ProcessOptions {
// Core options
processId?: string; // Custom process ID
metadata?: unknown; // Custom metadata
// Progress tracking
onProgress?: (progress: ProgressUpdate) => void; // Progress callback
updateEvery?: number; // Update frequency
progressDisplay?: ProgressDisplayOptions | boolean; // Built-in display
// Lifecycle callbacks
onDimensionStart?: (dimension: string) => void;
onDimensionComplete?: (dimension: string, result: DimensionResult) => void;
onSectionStart?: (index: number, total: number) => void;
onSectionComplete?: (index: number, total: number) => void;
onError?: (context: string, error: Error) => void;
// Additional custom options
[key: string]: unknown;
}Example:
const result = await engine.process(sections, {
processId: 'custom-id-123',
metadata: { userId: 456, environment: 'production' },
onProgress: (progress) => {
console.log(`${progress.percent}% - $${progress.cost}`);
},
onDimensionStart: (dimension) => {
console.log(`Starting: ${dimension}`);
},
onDimensionComplete: (dimension, result) => {
if (result.error) {
console.error(`${dimension} failed:`, result.error);
} else {
console.log(`${dimension} completed`);
}
},
onError: (context, error) => {
console.error(`Error in ${context}:`, error.message);
},
progressDisplay: {
display: 'bar',
showDimensions: true
}
});Error & Skip Types
RetryContext
Context for handleRetry hook.
interface RetryContext extends ProviderContext {
error: Error; // The error that occurred
attempt: number; // Current attempt (1-based)
maxAttempts: number; // Max attempts configured
previousAttempts: Array<{ // History of previous attempts
attempt: number;
error: Error;
provider: string;
timestamp: number;
}>;
}Example:
handleRetry(context: RetryContext): RetryResponse {
console.log(`Retry attempt ${context.attempt}/${context.maxAttempts}`);
console.log(`Error: ${context.error.message}`);
// Custom exponential backoff
const delayMs = Math.pow(2, context.attempt) * 1000;
// Don't retry rate limit errors
if (context.error.message.includes('rate limit')) {
return { shouldRetry: false };
}
// Don't retry after 5 attempts
if (context.attempt >= 5) {
return { shouldRetry: false };
}
return { shouldRetry: true, delayMs };
}RetryResponse
Response from handleRetry hook.
interface RetryResponse {
shouldRetry?: boolean; // Override retry decision
delayMs?: number; // Custom delay before retry
modifiedRequest?: ProviderRequest; // Modified request for retry
modifiedProvider?: string; // Switch provider
}Example:
// Simple retry with delay
return { delayMs: 2000 };
// Don't retry
return { shouldRetry: false };
// Modify request for retry
return {
modifiedRequest: {
...context.request,
options: {
...context.request.options,
temperature: 0.5 // Increase temperature
}
}
};
// Switch to different model
return {
modifiedRequest: {
...context.request,
options: { model: 'claude-3-7-sonnet-20250219' }
}
};FallbackContext
Context for handleProviderFallback hook.
interface FallbackContext extends RetryContext {
failedProvider: string; // The provider that failed
fallbackProvider: string; // The fallback being tried
fallbackOptions: Record<string, unknown>; // Fallback provider options
}Example:
async handleProviderFallback(
context: FallbackContext
): Promise<FallbackResponse> {
console.log(`${context.failedProvider} failed, trying ${context.fallbackProvider}`);
// Wait before trying fallback
return {
shouldFallback: true,
delayMs: 1000
};
}FallbackResponse
Response from handleProviderFallback hook.
interface FallbackResponse {
shouldFallback?: boolean; // Override fallback decision
delayMs?: number; // Delay before trying fallback
modifiedRequest?: ProviderRequest; // Modified request
}Example:
// Allow fallback with delay
return {
shouldFallback: true,
delayMs: 2000
};
// Skip fallback
return { shouldFallback: false };
// Modify request for fallback
return {
modifiedRequest: {
...context.request,
input: simplifiedPrompt
}
};FailureContext
Context for handleDimensionFailure hook.
interface FailureContext extends RetryContext {
totalAttempts: number; // Total attempts made
providers: string[]; // All providers tried
}Example:
async handleDimensionFailure(
context: FailureContext
): Promise<DimensionResult | void> {
console.error(`All providers failed for ${context.dimension}`);
console.error(`Tried: ${context.providers.join(', ')}`);
console.error(`Total attempts: ${context.totalAttempts}`);
// Return fallback result
return {
data: {
fallback: true,
defaultValue: null
},
metadata: {
failed: true,
error: context.error.message
}
};
}SkipWithResult
Return type for skip hooks when providing cached result.
interface SkipWithResult {
skip: true;
result: DimensionResult;
}Example:
async shouldSkipSectionDimension(
context: SectionDimensionContext
): Promise<boolean | SkipWithResult> {
// Simple skip
if (context.section.content.length < 50) {
return true;
}
// Skip with cached result
const cacheKey = `${context.dimension}:${context.section.metadata.id}`;
const cached = await redis.get(cacheKey);
if (cached) {
return {
skip: true,
result: {
data: JSON.parse(cached),
metadata: {
cached: true,
cacheKey,
timestamp: Date.now()
}
}
};
}
return false;
}Type Guards
Utility functions for type checking at runtime.
isSkipWithResult
Check if skip result includes a cached result.
function isSkipWithResult(
result: boolean | SkipWithResult
): result is SkipWithResultExample:
const skipResult = await plugin.shouldSkipSectionDimension(context);
if (isSkipWithResult(skipResult)) {
// Use cached result
console.log('Using cached result:', skipResult.result.data);
return skipResult.result;
} else if (skipResult === true) {
// Skip without result
return { metadata: { skipped: true } };
} else {
// Don't skip - execute normally
return await executeNormally();
}isErrorResult
Check if dimension result is an error.
function isErrorResult(
result: DimensionResult
): result is { error: string }Example:
const result = section.results.sentiment;
if (isErrorResult(result)) {
console.error('Dimension failed:', result.error);
console.error('Provider:', result.metadata?.provider);
} else {
console.log('Sentiment:', result.data.sentiment);
}isSuccessResult
Check if dimension result has data.
function isSuccessResult(
result: DimensionResult
): result is { data: unknown }Example:
const result = section.results.sentiment;
if (isSuccessResult(result)) {
console.log('Success:', result.data);
console.log('Model:', result.metadata?.model);
console.log('Tokens:', result.metadata?.tokens);
console.log('Cost:', result.metadata?.cost);
} else if (isErrorResult(result)) {
console.error('Error:', result.error);
} else {
console.log('Skipped');
}Quick Reference
Core Data Flow
// 1. Input
const sections: SectionData[] = [
{ content: '...', metadata: { id: 1 } }
];
// 2. Execute
const result: ProcessResult = await engine.process(sections);
// 3. Access section results
result.sections.forEach(sectionResult => {
const section: SectionData = sectionResult.section;
const results: Record<string, DimensionResult> = sectionResult.results;
const sentiment: DimensionResult = results.sentiment;
const data = sentiment.data;
const metadata: ProviderMetadata = sentiment.metadata;
});
// 4. Access global results
const summary = result.globalResults.overall_summary?.data;
// 5. Access costs
const totalCost = result.costs?.totalCost;
const dimensionCost = result.costs?.byDimension.sentiment?.cost;Context Hierarchy
BaseContext
├─ ProcessContext
│ ├─ BeforeProcessStartContext
│ ├─ ProcessResultContext
│ └─ ProcessFailureContext
├─ DimensionContext
│ ├─ SectionDimensionContext
│ ├─ ProviderContext
│ │ ├─ ProviderResultContext
│ │ └─ RetryContext
│ │ ├─ FallbackContext
│ │ └─ FailureContext
│ ├─ DimensionResultContext
│ │ └─ TransformSectionsContext
│ └─ FinalizeContext
└─ PromptContext (standalone)Common Patterns
Accessing section results:
const sentiment = result.sections[0].results.sentiment?.data;Accessing global results:
const summary = result.globalResults.overall_summary?.data;Accessing costs:
const totalCost = result.costs?.totalCost;
const dimensionCost = result.costs?.byDimension.sentiment?.cost;Checking for errors:
if (result.error) {
console.error('Failed:', result.error);
} else if (result.data) {
console.log('Success:', result.data);
}Type-safe dependency access:
interface SentimentData {
sentiment: 'positive' | 'negative' | 'neutral';
score: number;
}
const sentiment = context.dependencies.sentiment as
DimensionResult<SentimentData> | undefined;
if (sentiment?.data) {
const score: number = sentiment.data.score;
}Using type guards:
if (isErrorResult(result)) {
console.error('Error:', result.error);
} else if (isSuccessResult(result)) {
console.log('Data:', result.data);
} else {
console.log('Skipped');
}Progress tracking:
await engine.process(sections, {
onProgress: (progress: ProgressUpdate) => {
console.log(`${progress.percent}% - $${progress.cost}`);
}
});Skip with cached result:
const skipResult = await plugin.shouldSkipSectionDimension(context);
if (isSkipWithResult(skipResult)) {
return skipResult.result; // Use cached
}