Quick Start
Get started with dagengine in 5 minutes. Build a simple sentiment analysis workflow.
Installation
npm install @dagengine/coreyarn add @dagengine/corepnpm add @dagengine/coreRequirements: Node.js ≥ 18.0.0, TypeScript ≥ 5.0 (recommended)
Your First Workflow
Let's analyze customer reviews with sentiment analysis, topic extraction, and summaries.
Step 1: Set Your API Key
export ANTHROPIC_API_KEY="your-key-here"Get your API key from Anthropic Console.
Step 2: Create Your Plugin
A plugin defines what analyses to run. Here's a complete review analyzer:
import { DagEngine, Plugin, type PromptContext, type ProviderSelection } from '@dagengine/core';
// Define result types (optional but helps with TypeScript)
interface SentimentResult {
sentiment: "positive" | "negative" | "neutral";
score: number;
}
interface TopicsResult {
topics: string[];
}
interface SummaryResult {
summary: string;
}
class ReviewAnalyzer extends Plugin {
constructor() {
super('analyzer', 'Review Analyzer', 'Analyzes customer reviews');
this.dimensions = ['sentiment', 'topics', 'summary'];
}
defineDependencies(): Record<string, string[]> {
return {
summary: ['sentiment', 'topics']
};
}
createPrompt(context: PromptContext): string {
const content = context.sections[0]?.content || '';
if (context.dimension === 'sentiment') {
return `Analyze sentiment: "${content}"
Return JSON: {"sentiment": "positive|negative|neutral", "score": 0-1}`;
}
if (context.dimension === 'topics') {
return `Extract topics: "${content}"
Return JSON: {"topics": ["topic1", "topic2"]}`;
}
if (context.dimension === 'summary') {
const sentiment = context.dependencies.sentiment?.data as SentimentResult;
const topics = context.dependencies.topics?.data as TopicsResult;
return `Create a ${sentiment.sentiment} summary covering ${topics.topics.join(', ')}:
"${content}"
Return JSON: {"summary": "summary text"}`;
}
throw new Error(`Unknown dimension: ${context.dimension}`);
}
selectProvider(): ProviderSelection {
return {
provider: 'anthropic',
options: { model: 'claude-3-5-haiku-20241022' }
};
}
}Step 3: Process Your Data
async function main(): Promise<void> {
// Validate API key
if (!process.env.ANTHROPIC_API_KEY) {
console.error('❌ Missing ANTHROPIC_API_KEY environment variable');
console.error('Set it with: export ANTHROPIC_API_KEY="your-key"');
process.exit(1);
}
// Create engine
const engine = new DagEngine({
plugin: new ReviewAnalyzer(),
providers: {
anthropic: { apiKey: process.env.ANTHROPIC_API_KEY },
}
});
// Prepare reviews
const reviews = [
{ content: 'This product is amazing! Love it!', metadata: { id: 1 } },
{ content: 'Terrible quality. Very disappointed.', metadata: { id: 2 } },
{ content: 'It works as expected.', metadata: { id: 3 } }
];
// Process
const result = await engine.process(reviews);
// Display results
result.sections.forEach((section, i) => {
const sentiment = section.results.sentiment?.data as SentimentResult;
const topics = section.results.topics?.data as TopicsResult;
const summary = section.results.summary?.data as SummaryResult;
console.log(`Review ${i + 1}:`);
console.log(` Sentiment: ${sentiment.sentiment} (${sentiment.score})`);
console.log(` Topics: ${topics.topics.join(', ')}`);
console.log(` Summary: ${summary.summary}`);
console.log('---');
});
}
// Run with error handling
main().catch((error: Error) => {
console.error('❌ Processing failed:', error.message);
process.exit(1);
});Output:
Review 1:
Sentiment: positive (0.95)
Topics: product quality, satisfaction
Summary: A highly positive review expressing love for the product
---
Review 2:
Sentiment: negative (0.15)
Topics: quality issues, disappointment
Summary: A strongly negative review criticizing poor quality
---
Review 3:
Sentiment: neutral (0.5)
Topics: functionality
Summary: A neutral assessment confirming expected functionality
---What Just Happened?
dagengine automatically optimized your workflow:
- ✅ Parallel execution:
sentimentandtopicsran simultaneously (both have no dependencies) - ✅ Smart ordering:
summarywaited for both to complete - ✅ Batch processing: All 3 reviews processed in parallel
- ✅ Zero orchestration: 9 AI calls (3 reviews × 3 dimensions) optimized automatically
Understanding the Results
The process() method returns structured results:
{
sections: [
{
section: { content: '...', metadata: { id: 1 } },
results: {
sentiment: {
data: { sentiment: 'positive', score: 0.95 },
metadata: {
provider: 'anthropic',
model: 'claude-3-5-haiku-20241022',
tokens: { inputTokens: 45, outputTokens: 12 },
cost: { inputCost: 0.000045, outputCost: 0.00015 }
}
},
topics: { /* ... */ },
summary: { /* ... */ }
}
},
// ... more sections
],
globalResults: {},
stats: {
totalCost: 0.025,
totalTokens: 1543,
dimensions: { /* per-dimension stats */ }
}
}Key parts:
sections- Results for each input sectionresults[dimension].data- Your analysis resultresults[dimension].metadata- Provider info, tokens, and costsstats- Aggregate cost and token tracking
Minimal Example
For a simpler starting point, here's a basic sentiment analyzer:
import { DagEngine, Plugin, type PromptContext, type ProviderSelection } from '@dagengine/core';
class SentimentPlugin extends Plugin {
constructor() {
super('sentiment', 'Sentiment Analyzer', 'Analyzes text sentiment');
this.dimensions = ['sentiment'];
}
createPrompt(context: PromptContext): string {
return `Analyze the sentiment: "${context.sections[0]?.content}"
Return JSON: {"sentiment": "positive|negative|neutral", "score": 0-1}`;
}
selectProvider(): ProviderSelection {
return {
provider: 'anthropic',
options: { model: 'claude-3-5-haiku-20241022' }
};
}
}
// Create engine
const engine = new DagEngine({
plugin: new SentimentPlugin(),
providers: {
anthropic: { apiKey: process.env.ANTHROPIC_API_KEY },
}
});
// Process data
engine.process([
{ content: 'I love this!', metadata: {} }
]).then((result) => {
console.log(result.sections[0]?.results.sentiment?.data);
// { sentiment: 'positive', score: 0.95 }
});What's Next?
You've learned the basics! Now explore:
Core Concepts
- Core Concepts - Deep dive into sections, dimensions, and dependencies
- Configuration - All engine configuration options
Advanced Features
Multiple Providers:
selectProvider(dimension: string): ProviderSelection {
if (dimension === 'quality_check') {
return { provider: 'gemini', options: { model: 'gemini-1.5-flash' } };
}
return { provider: 'anthropic', options: { model: 'claude-3-5-haiku-20241022' } };
}Provider Fallbacks:
selectProvider(): ProviderSelection {
return {
provider: 'anthropic',
options: { model: 'claude-3-5-haiku-20241022' },
fallbacks: [
{ provider: 'openai', options: { model: 'gpt-4o-mini' } },
{ provider: 'gemini', options: { model: 'gemini-1.5-flash' } }
]
};
}Cost Optimization:
shouldSkipSectionDimension(context: SkipContext): boolean {
if (context.dimension === 'deep_analysis') {
const quality = context.dependencies.quality_check?.data as { score: number };
return quality.score < 0.7; // Skip low-quality items
}
return false;
}Lifecycle Hooks:
async afterDimensionExecute(context: AfterDimensionExecuteContext): Promise<void> {
// Save results to database
await db.results.insert({
sectionId: context.section.metadata.id,
dimension: context.dimension,
data: context.result.data
});
}Step-by-Step Guides
Work through our fundamentals series:
- Hello World - Your first plugin
- Dependencies - Control execution order
- Section vs Global - Two dimension types
- Transformations - Reshape data mid-pipeline
- Skip Logic - Optimize costs
- Multi-Provider - Route to different models
- Async Hooks - Database integration
- Error Handling - Graceful recovery
Common Issues
"Provider not found"
Problem
const engine = new DagEngine({
plugin: new SentimentPlugin(),
providers: {} // ❌ Empty!
});Solution
const engine = new DagEngine({
plugin: new SentimentPlugin(),
providers: {
anthropic: { apiKey: process.env.ANTHROPIC_API_KEY }
}
});"API key not set"
Problem
Error: Anthropic API key is requiredSolution
# Set environment variable
export ANTHROPIC_API_KEY="sk-ant-..."
# Or use .env file
echo "ANTHROPIC_API_KEY=sk-ant-..." > .envThen install dotenv:
npm install dotenvAnd load it in your code:
import 'dotenv/config';Result is undefined
Problem
console.log(result.sections[0].results.sentiment);
// undefinedCause
Dimension name mismatch or missing optional chaining
Solution
// Plugin dimension name must match
this.dimensions = ['sentiment']; // ✅
// Use optional chaining for safety
const data = result.sections[0]?.results.sentiment?.data; // ✅TypeScript errors
Problem
Property 'sentiment' does not exist on type '{}'Solution
Define result types and use type assertions:
interface SentimentResult {
sentiment: string;
score: number;
}
const data = section.results.sentiment?.data as SentimentResult;Need Help?
- 💬 Ask a Question - Get help from the community
- 🐛 Report a Bug - Found an issue?
- 📖 Read the Docs - Comprehensive guides and API reference