diff --git a/src/data/guides.json b/src/data/guides.json index ff21c00a..e496c5f4 100644 --- a/src/data/guides.json +++ b/src/data/guides.json @@ -157,5 +157,148 @@ "Retention and archival: logs grow quickly. Implement rotation (keep 30 days of detailed logs), archival (compress and store older logs), and cleanup (delete ancient logs). Balance debuggability with storage costs." ], "tags": ["monitoring", "observability", "logging", "metrics", "debugging"] + }, + { + "slug": "agent-communication-patterns", + "title": "Agent Communication Patterns", + "description": "Master the core communication patterns for AI agents: request-response, pub-sub, event-driven, streaming, and polling. Choose the right pattern for your use case.", + "difficulty": "Intermediate", + "category": "Communication", + "estimatedMinutes": 35, + "content": [ + "Communication patterns are the foundation of how agents interact with systems, services, and each other. Choosing the right pattern makes the difference between a brittle, hard-to-scale system and one that's robust and flexible.", + "**Request-Response** is the simplest pattern: agent sends a request, waits for response, processes result. Perfect for synchronous operations like API calls, database queries, or tool invocations. Use when you need immediate results and can afford to wait.", + "Example: Agent calls a weather API, waits for JSON response, extracts temperature, and reports back. Simple, predictable, but blocks until response arrives. Best for quick operations (<5 seconds).", + "**Publish-Subscribe (Pub-Sub)** decouples senders from receivers. Agents publish events to topics; subscribers receive events they're interested in. Perfect for broadcasting updates, notifications, or when multiple agents need the same data.", + "Example: A monitoring agent publishes 'system_alert' events. Multiple agents subscribe: one logs to database, another sends notifications, a third updates dashboards. No agent knows about the others—they just react to events.", + "**Event-Driven Architecture** treats everything as events. Agents react to state changes rather than polling for updates. Highly scalable and decoupled, but requires robust event infrastructure (event bus, message queue).", + "Example: File uploaded → triggers processing agent → triggers analysis agent → triggers notification agent. Each agent is independent, work flows through the system automatically, and new agents can join the chain without code changes.", + "**Streaming** is for continuous data flows. Agent establishes a connection and receives data incrementally as it becomes available. Perfect for real-time feeds, live updates, or processing large datasets in chunks.", + "Example: LLM streaming responses, real-time sensor data, log tailing, chat messages. Agent processes tokens as they arrive rather than waiting for complete response. Better UX and lower latency.", + "**Polling** is when agents periodically check for changes. Simple but inefficient—generates unnecessary traffic and introduces latency. Use only when push-based patterns aren't available (legacy APIs, systems without webhooks).", + "Example: Agent checks email inbox every 5 minutes. Most checks find nothing new, wasting resources. Better: use IMAP IDLE or webhooks if available. Polling should be your last resort.", + "**Pattern Comparison**: Request-response for immediate needs, pub-sub for broadcasting, events for workflows, streaming for real-time data, polling when nothing else works. Consider latency requirements, scalability needs, and infrastructure complexity.", + "**Choosing the Right Pattern**: Ask: Do I need immediate response? (Request-response). Multiple consumers? (Pub-sub). Complex workflow? (Event-driven). Real-time data? (Streaming). No better option? (Polling).", + "**Implementation Tips**: Start simple with request-response. Add pub-sub when you need broadcasting. Introduce event-driven architecture when workflows get complex. Use streaming for user-facing real-time features. Avoid polling unless forced.", + "**Error Handling**: Each pattern has different failure modes. Request-response: retry with exponential backoff. Pub-sub: dead letter queues for failed events. Event-driven: compensating transactions. Streaming: reconnection logic. Polling: circuit breakers.", + "**Real-World Example**: An agent system handling user requests. Request-response for database queries, pub-sub for notifications, event-driven for multi-step workflows, streaming for LLM responses, polling for legacy email integration. Multiple patterns coexist." + ], + "tags": ["communication", "patterns", "architecture", "messaging"] + }, + { + "slug": "multi-agent-communication", + "title": "Multi-Agent Communication Patterns", + "description": "Design robust multi-agent systems with proven patterns: orchestrator, choreography, blackboard, market-based, and hierarchical. Build teams of specialized agents that work together seamlessly.", + "difficulty": "Advanced", + "category": "Communication", + "estimatedMinutes": 55, + "content": [ + "Multi-agent systems are where AI gets really powerful—but also complex. The key is choosing the right communication pattern for how your agents coordinate. Pick wrong, and you get chaos. Pick right, and you get emergent intelligence.", + "**Orchestrator Pattern** uses a central coordinator that directs all agent interactions. The orchestrator receives tasks, breaks them down, assigns work to specialized agents, monitors progress, and assembles results. Think of it as a conductor leading an orchestra.", + "Orchestrator example: User requests 'Write a blog post about AI.' Orchestrator assigns research to ResearchAgent, writing to WriterAgent, editing to EditorAgent, and image generation to DesignAgent. It tracks state, handles failures, and delivers the final post.", + "**Orchestrator Pros**: Centralized control, easy to debug, clear accountability, simple failure handling. **Cons**: Single point of failure, bottleneck at scale, tight coupling. **When to use**: Complex workflows with clear steps, need for strong consistency.", + "```typescript\nclass Orchestrator {\n async executeWorkflow(task: Task) {\n const research = await this.researchAgent.execute(task);\n const draft = await this.writerAgent.execute(research);\n const edited = await this.editorAgent.execute(draft);\n const final = await this.designAgent.addImages(edited);\n return final;\n }\n}\n```", + "**Choreography Pattern** has no central coordinator. Agents know their roles and react to events from other agents. Each agent observes the system, decides when to act, and publishes results for others. Like dancers following music, not a choreographer.", + "Choreography example: FileUploadedEvent → ProcessingAgent downloads and analyzes → AnalysisCompleteEvent → NotificationAgent sends email → EmailSentEvent → AuditAgent logs activity. No central control, fully decentralized.", + "**Choreography Pros**: No single point of failure, scales horizontally, loose coupling. **Cons**: Hard to debug, difficult to understand system behavior, eventual consistency challenges. **When to use**: High scalability needs, independent agent teams, event-driven systems.", + "```typescript\nclass ProcessingAgent {\n async onEvent(event: Event) {\n if (event.type === 'FileUploaded') {\n const result = await this.process(event.data);\n await this.eventBus.publish('AnalysisComplete', result);\n }\n }\n}\n```", + "**Blackboard Pattern** uses a shared knowledge space where agents read and write data. Agents monitor the blackboard, contribute their expertise when relevant, and build on each other's work. Think of it as a shared whiteboard for problem-solving.", + "Blackboard example: Complex data analysis task. StatisticsAgent posts descriptive stats → PatternAgent identifies trends → PredictionAgent builds forecasts → ValidationAgent checks assumptions. Each adds to shared understanding.", + "**Blackboard Pros**: Flexible, supports parallel work, agents can join/leave dynamically. **Cons**: Race conditions, requires locking/versioning, can become messy. **When to use**: Exploratory tasks, multiple perspectives needed, incremental problem-solving.", + "```typescript\nclass Blackboard {\n private data: Map = new Map();\n async write(key: string, value: any, agentId: string) {\n await this.lock(key);\n this.data.set(key, { value, agentId, timestamp: Date.now() });\n await this.notify('dataUpdated', { key, agentId });\n }\n}\n```", + "**Market-Based Pattern** treats agent coordination as an economic system. Tasks have prices, agents bid based on capability and workload, and tasks go to the best bidder. Self-organizing and efficient under the right conditions.", + "Market example: Translation task posted with budget. EnglishAgent bids $0.50/word, FrenchAgent bids $0.40/word (less busy), SpanishAgent bids $0.60/word (specialized). FrenchAgent wins, executes task, receives payment (priority tokens).", + "**Market Pros**: Automatic load balancing, agents optimize for efficiency, scales well. **Cons**: Complex to implement, requires pricing mechanism, can be unpredictable. **When to use**: Resource allocation, load balancing, heterogeneous agent capabilities.", + "```typescript\nclass MarketCoordinator {\n async auctionTask(task: Task) {\n const bids = await this.collectBids(task);\n const winner = bids.reduce((best, bid) => \n bid.price < best.price && bid.quality >= task.minQuality ? bid : best\n );\n return await winner.agent.execute(task);\n }\n}\n```", + "**Hierarchical Pattern** organizes agents in a tree structure. Higher-level agents delegate to lower-level specialists. Combines orchestration's control with choreography's distribution. Military command structure for agents.", + "Hierarchical example: CEO agent receives quarterly planning request → delegates to DepartmentAgents (Sales, Engineering, Marketing) → each delegates to TeamAgents → TeamAgents coordinate individual WorkerAgents. Clear authority, distributed execution.", + "**Hierarchical Pros**: Scalable, clear responsibility, local autonomy with global coordination. **Cons**: Communication overhead, rigid structure, potential for local optimization over global. **When to use**: Large agent teams, clear organizational structure, need for accountability.", + "```typescript\nclass ManagerAgent {\n private team: Agent[];\n async delegateTask(task: Task) {\n const subtasks = this.decompose(task);\n const results = await Promise.all(\n subtasks.map(st => this.findBestAgent(st).execute(st))\n );\n return this.synthesize(results);\n }\n}\n```", + "**Pattern Selection Guide**: Simple workflow with clear steps? → Orchestrator. Need massive scale and resilience? → Choreography. Exploratory problem-solving? → Blackboard. Resource optimization? → Market-based. Large team with hierarchy? → Hierarchical.", + "**Hybrid Approaches**: Real systems often combine patterns. Hierarchical at the top for organization, orchestration within teams for workflows, market-based for resource allocation, blackboard for collaborative analysis. Don't be dogmatic—use what works.", + "**Communication Protocols**: Regardless of pattern, define clear message formats (JSON schemas), communication channels (message queues, shared files, API endpoints), and error handling. Consistency across agents prevents integration nightmares.", + "**Failure Handling**: Orchestrator: retry failed steps, rollback on error. Choreography: dead letter queue, compensating events. Blackboard: version conflict resolution. Market: task reposting, reputation systems. Hierarchical: escalation to higher levels.", + "**Testing Strategies**: Unit test individual agents, integration test communication flows, chaos test failure scenarios (random agent crashes, network partitions, message loss). Multi-agent systems have emergent behaviors—test for them.", + "**Start Simple, Evolve**: Begin with orchestrator (easiest to understand). Add choreography for scalability. Introduce blackboard for complex problems. Consider market-based for advanced optimization. Build hierarchies as team grows. Complexity should match needs." + ], + "tags": ["multi-agent", "coordination", "patterns", "distributed-systems", "architecture"] + }, + { + "slug": "human-agent-interaction", + "title": "Human-Agent Interaction Patterns", + "description": "Design effective human-in-the-loop systems. Master approval workflows, escalation strategies, feedback loops, progressive disclosure, and confidence thresholds for safe, transparent agent collaboration.", + "difficulty": "Intermediate", + "category": "Communication", + "estimatedMinutes": 45, + "content": [ + "The most effective AI systems aren't fully autonomous—they're collaborative. Human-agent interaction patterns determine when agents act independently, when they ask for guidance, and how they learn from human feedback. Get this right, and you amplify both human and agent capabilities.", + "**Approval Workflows** are the foundation of safe agent operation. Define which actions require human approval before execution. Low-risk operations (reading files, web search) can proceed autonomously. High-risk operations (sending emails, making purchases, deleting data) require explicit approval.", + "Implementation example: Agent wants to send an email. Before sending, it presents: draft email content, recipient list, subject line, and asks 'Send this email? (yes/no/edit)'. User can approve, reject, or request modifications. Only after explicit approval does the agent proceed.", + "```typescript\nclass ApprovalWorkflow {\n async executeWithApproval(action: Action) {\n if (this.requiresApproval(action)) {\n const preview = await action.preview();\n const decision = await this.requestApproval(preview);\n if (decision === 'approved') return await action.execute();\n if (decision === 'edit') return await this.executeWithApproval(action.modify());\n return 'cancelled';\n }\n return await action.execute();\n }\n}\n```", + "**Escalation Strategies** define when agents should escalate to humans. Set confidence thresholds: if agent confidence < 70%, ask for guidance. Use context awareness: escalate during business hours, log and defer during off-hours. Distinguish urgency levels.", + "Escalation triggers: low confidence in decision, conflicting data sources, unusual patterns detected, user-defined critical paths, errors after multiple retries, actions outside normal parameters. Each trigger should have a clear escalation path.", + "Example escalation flow: Agent encounters ambiguous task → checks knowledge base (no match) → confidence score 45% → checks if business hours → yes → sends Slack notification with context and options → waits for human decision with 30min timeout → if no response, logs and defers.", + "```typescript\nclass EscalationManager {\n async handleUncertainty(decision: Decision) {\n if (decision.confidence < 0.7) {\n if (this.isBusinessHours() && decision.priority === 'high') {\n return await this.escalateImmediate(decision);\n }\n await this.logForReview(decision);\n return 'deferred';\n }\n }\n}\n```", + "**Feedback Loops** are how agents learn from human corrections. When a human modifies agent output or overrides a decision, capture that feedback. Use it to improve future decisions, update knowledge base, and refine confidence models.", + "Feedback types: explicit corrections ('not that, this'), preference indicators (user always chooses option A over B), outcome data (email sent got positive reply vs. no response), quality ratings (1-5 stars on agent output).", + "Implementation: Track all human interventions. Store decision context, agent's original choice, human's correction, and outcome. Periodically analyze patterns. If human consistently corrects X → agent should learn to handle X differently or ask first.", + "```typescript\nclass FeedbackLoop {\n async captureCorrection(original: Action, corrected: Action, context: Context) {\n await this.store({\n timestamp: Date.now(),\n original,\n corrected,\n context,\n pattern: this.extractPattern(original, corrected)\n });\n await this.updateConfidenceModel();\n }\n}\n```", + "**Progressive Disclosure** manages information complexity. Don't overwhelm users with every detail—show what's relevant when it's relevant. Start with summary, allow drilling down for details. Let users control information density.", + "Example: Agent completes research task. Initial notification: 'Research complete: Found 12 sources, 3 key insights.' User can expand to see: list of sources, summary of each insight, or request full detailed report. User controls depth.", + "UX patterns: Summary first, details on demand. Use progressive disclosure for: agent reasoning (show decision, hide thought process unless asked), data processing (show results, hide intermediate steps), error details (show impact, hide stack trace unless debugging).", + "```typescript\nclass ProgressiveDisclosure {\n getResponse(level: 'summary' | 'detailed' | 'full') {\n const response = { summary: this.getSummary() };\n if (level === 'detailed' || level === 'full') {\n response.details = this.getDetails();\n }\n if (level === 'full') {\n response.raw = this.getRawData();\n response.reasoning = this.getReasoningTrace();\n }\n return response;\n }\n}\n```", + "**Confidence Thresholds** determine when agents act vs. ask. Define thresholds for different action types. Critical actions: 95%+ confidence. Moderate actions: 80%+ confidence. Low-risk actions: 60%+ confidence. Below threshold → ask human.", + "Confidence calculation: Combine multiple factors. Data quality (source reliability), pattern match (similar past success), context completeness (all required info present), model certainty (LLM logprobs), user history (similar requests before).", + "Dynamic thresholds: Adjust based on stakes. Financial transactions require higher confidence than calendar entries. User-specific thresholds: experienced users may accept 70% confidence, new users need 90%. Time-aware: lower threshold for reversible actions.", + "```typescript\nclass ConfidenceManager {\n shouldAutoExecute(action: Action, confidence: number): boolean {\n const threshold = this.getThreshold(action.riskLevel, action.reversible);\n if (confidence >= threshold) return true;\n if (confidence >= threshold - 0.1 && this.userPreference === 'aggressive') return true;\n return false;\n }\n}\n```", + "**UX Guidelines for Agent Interactions**: Be transparent—explain what agent is doing and why. Be interruptible—allow users to stop or modify in-progress actions. Be reversible—provide undo for actions when possible. Be educational—help users understand agent capabilities and limitations.", + "**Communication Patterns**: For approvals: show clear preview, highlight risks, provide options (approve/reject/modify). For escalations: include context, suggest options, respect user time. For feedback: make it effortless (thumbs up/down), respect user choice (don't nag for feedback).", + "**Trust Building**: Start conservative (high thresholds, frequent approvals). As user trusts grows, offer to reduce approvals for routine tasks. Track success rate—if agent gets it right 95% of the time, user can confidently approve less. Trust is earned through consistency.", + "**Error Recovery**: When agent makes mistakes, own them clearly: 'I sent email to wrong recipient. Here's what happened, here's how we can fix it.' Provide immediate correction options. Learn from errors—similar mistakes should trigger approvals in future.", + "**Proactive Communication**: Agent should initiate communication when: high-value information discovered, potential problems detected, task completed, stuck and needs help, significant decision pending. Don't interrupt for routine operations.", + "**Notification Strategy**: Use urgency levels. Critical: immediate (phone notification). Important: timely (Slack message). Informational: batched (daily digest). User should control notification preferences per category.", + "**Real-World Example**: Email management agent. Auto-archive newsletters (low-risk, 60% confidence needed). Suggest replies for routine emails (medium-risk, 80% confidence, show preview). Flag suspicious emails immediately (high-value, proactive). Escalate important emails from VIPs (high-stakes, always notify).", + "**Testing Human-Agent Interaction**: Test approval flows with real users. Measure: approval request frequency, approval rate, time to decision, user frustration indicators. Optimize for minimum interruption with maximum safety. Balance is key." + ], + "tags": ["human-in-the-loop", "interaction", "approval", "escalation", "ux", "feedback"] + }, + { + "slug": "event-driven-agents", + "title": "Event-Driven Architecture for Agents", + "description": "Build scalable, resilient agent systems with event sourcing. Master event store design, CQRS patterns, saga orchestration, and dead letter queues. Handle complex workflows with confidence.", + "difficulty": "Advanced", + "category": "Communication", + "estimatedMinutes": 60, + "content": [ + "Event-driven architecture (EDA) is the backbone of scalable, resilient agent systems. Instead of storing current state, you store a sequence of events that led to that state. This unlocks powerful capabilities: complete audit trails, time-travel debugging, event replay, and decoupled agents that react independently to changes.", + "**Core Concept**: Every state change is an event. Don't store 'user email is xyz@example.com'—store 'UserEmailUpdated(xyz@example.com) at timestamp T'. Current state is derived by replaying events. This shift in thinking enables capabilities impossible with traditional state storage.", + "**Event Store Design** is the foundation. An event store is an append-only log of events. Each event has: unique ID, timestamp, event type, aggregate ID (entity it relates to), payload (event data), metadata (agent ID, correlation ID, causation ID).", + "```typescript\ninterface Event {\n id: string; // UUID for this event\n timestamp: number; // Unix timestamp\n type: string; // 'TaskCreated', 'AgentAssigned', etc.\n aggregateId: string; // ID of entity (task, user, etc.)\n payload: any; // Event-specific data\n metadata: {\n agentId: string; // Which agent created event\n correlationId: string; // Trace related events\n causationId?: string; // Event that triggered this one\n };\n}\n```", + "**Event Store Implementation**: Use append-only storage. PostgreSQL with events table works well. For scale: specialized stores like EventStoreDB. Critical: events are immutable once written. Never update or delete events—only append corrections.", + "```typescript\nclass EventStore {\n async append(event: Event): Promise {\n await this.db.query(\n 'INSERT INTO events (id, timestamp, type, aggregate_id, payload, metadata) VALUES ($1, $2, $3, $4, $5, $6)',\n [event.id, event.timestamp, event.type, event.aggregateId, event.payload, event.metadata]\n );\n await this.publishToSubscribers(event);\n }\n\n async getEvents(aggregateId: string): Promise {\n return await this.db.query('SELECT * FROM events WHERE aggregate_id = $1 ORDER BY timestamp', [aggregateId]);\n }\n}\n```", + "**CQRS (Command Query Responsibility Segregation)** separates reads from writes. Commands change state (append events), queries read state (from projections). This allows independent optimization: write side ensures consistency, read side optimizes for query patterns.", + "Command side: Validate command → Generate events → Append to event store → Publish events. Query side: Subscribe to events → Update read models (projections) → Serve queries from optimized read models. Complete decoupling of write and read paths.", + "```typescript\nclass TaskCommandHandler {\n async createTask(command: CreateTaskCommand) {\n // Validate\n if (!command.title) throw new Error('Title required');\n \n // Generate events\n const events = [\n { type: 'TaskCreated', aggregateId: command.taskId, payload: { title: command.title } },\n { type: 'TaskAssigned', aggregateId: command.taskId, payload: { agentId: command.agentId } }\n ];\n \n // Append to event store\n for (const event of events) await this.eventStore.append(event);\n }\n}\n\nclass TaskQueryHandler {\n async getTask(taskId: string) {\n // Query optimized read model, not event store\n return await this.readModel.findOne({ taskId });\n }\n}\n```", + "**Projections** (read models) are built by replaying events. Subscribe to event stream, update projection as events arrive. Multiple projections for different query needs: task list projection, agent workload projection, audit log projection.", + "```typescript\nclass TaskListProjection {\n async handleEvent(event: Event) {\n switch (event.type) {\n case 'TaskCreated':\n await this.db.insert('tasks', { id: event.aggregateId, ...event.payload, status: 'pending' });\n break;\n case 'TaskCompleted':\n await this.db.update('tasks', { id: event.aggregateId }, { status: 'completed', completedAt: event.timestamp });\n break;\n case 'TaskDeleted':\n await this.db.delete('tasks', { id: event.aggregateId });\n break;\n }\n }\n}\n```", + "**Saga Orchestration** manages long-running, multi-step workflows. A saga is a sequence of local transactions, each publishing events. If a step fails, compensating events undo previous steps. Critical for distributed agent coordination.", + "Example saga: Blog post creation. Steps: 1) Generate draft (WriterAgent), 2) Review quality (EditorAgent), 3) Generate images (DesignAgent), 4) Publish (PublishAgent). If step 3 fails → compensate by deleting draft and notifying user.", + "```typescript\nclass BlogPostSaga {\n async execute(command: CreateBlogPostCommand) {\n const sagaId = uuid();\n \n try {\n // Step 1: Generate draft\n await this.writerAgent.generateDraft(command);\n await this.eventStore.append({ type: 'DraftGenerated', aggregateId: sagaId });\n \n // Step 2: Review\n await this.editorAgent.review(command);\n await this.eventStore.append({ type: 'ReviewCompleted', aggregateId: sagaId });\n \n // Step 3: Generate images\n await this.designAgent.generateImages(command);\n await this.eventStore.append({ type: 'ImagesGenerated', aggregateId: sagaId });\n \n // Step 4: Publish\n await this.publishAgent.publish(command);\n await this.eventStore.append({ type: 'BlogPostPublished', aggregateId: sagaId });\n \n } catch (error) {\n // Compensate: undo completed steps\n await this.compensate(sagaId, error);\n throw error;\n }\n }\n \n async compensate(sagaId: string, error: Error) {\n const events = await this.eventStore.getEvents(sagaId);\n // Reverse order compensation\n if (events.some(e => e.type === 'ImagesGenerated')) {\n await this.designAgent.deleteImages(sagaId);\n }\n if (events.some(e => e.type === 'ReviewCompleted')) {\n await this.editorAgent.rollback(sagaId);\n }\n if (events.some(e => e.type === 'DraftGenerated')) {\n await this.writerAgent.deleteDraft(sagaId);\n }\n await this.eventStore.append({ type: 'SagaFailed', aggregateId: sagaId, payload: { error: error.message } });\n }\n}\n```", + "**Dead Letter Queues (DLQ)** handle events that can't be processed. When event processing fails after retries, move to DLQ for manual review. Prevents poison messages from blocking event stream. Critical for production resilience.", + "DLQ strategy: Retry failed event 3 times with exponential backoff (1s, 10s, 60s). After retries exhausted, move to DLQ with metadata: original event, error details, retry count. Alert ops team. Provide tools to inspect, fix, and replay DLQ events.", + "```typescript\nclass EventProcessor {\n async process(event: Event) {\n let attempts = 0;\n while (attempts < 3) {\n try {\n await this.handler.handle(event);\n return; // Success\n } catch (error) {\n attempts++;\n if (attempts >= 3) {\n // Move to DLQ\n await this.dlq.add({\n event,\n error: error.message,\n attempts,\n timestamp: Date.now()\n });\n await this.alertOps('Event processing failed', event);\n return;\n }\n await this.sleep(Math.pow(10, attempts) * 1000); // Exponential backoff\n }\n }\n }\n}\n```", + "**Event Versioning** handles schema evolution. Events are permanent—you can't change past events. Use versioning: TaskCreatedV1, TaskCreatedV2. Write upcasters that convert old events to new schema when replaying. Maintain backward compatibility.", + "```typescript\nclass EventUpcaster {\n upcast(event: Event): Event {\n if (event.type === 'TaskCreatedV1') {\n return {\n ...event,\n type: 'TaskCreatedV2',\n payload: {\n ...event.payload,\n priority: 'medium' // Default for V1 events\n }\n };\n }\n return event;\n }\n}\n```", + "**Idempotency** ensures processing events multiple times has same effect as once. Use event ID to track processed events. Before processing, check: 'Have I seen this event ID?' If yes, skip. If no, process and record ID. Critical for at-least-once delivery.", + "```typescript\nclass IdempotentEventHandler {\n async handle(event: Event) {\n if (await this.hasProcessed(event.id)) {\n console.log('Event already processed, skipping:', event.id);\n return;\n }\n \n await this.doWork(event);\n await this.markProcessed(event.id);\n }\n}\n```", + "**Event Sourcing Benefits**: Complete audit trail (who did what when), time-travel debugging (replay to any point), event replay (rebuild projections from scratch), temporal queries (what was state at time T?), analytics (analyze event patterns).", + "**Event Sourcing Challenges**: Eventual consistency (projections lag behind events), storage growth (events accumulate forever), complexity (more moving parts), debugging (distributed tracing needed). Not every system needs event sourcing—use when benefits outweigh costs.", + "**When to Use Event Sourcing**: Audit requirements (finance, healthcare, legal), complex domains (many state transitions), event replay needs (analytics, debugging), multi-agent coordination (decoupled agents reacting to events).", + "**When NOT to Use**: Simple CRUD apps (overkill), immediate consistency required (events are async), small team unfamiliar with pattern (learning curve), low event volume (traditional DB is fine).", + "**Testing Event-Sourced Systems**: Unit test event handlers (given events, verify state changes). Integration test sagas (verify compensation works). Chaos test event delivery (simulate network failures, duplicate events, out-of-order delivery).", + "**Production Considerations**: Snapshot state periodically (don't replay millions of events). Archive old events (keep recent in hot storage). Monitor DLQ size (spike indicates problem). Set up event replay tools (for disaster recovery).", + "**Real-World Example**: Multi-agent task system. TaskCreated event → AssignmentAgent picks agent → TaskAssigned event → WorkerAgent starts work → TaskStarted event → ProgressAgent updates dashboard. Complete decoupling, easy to add new agents that react to events." + ], + "tags": ["event-sourcing", "CQRS", "saga", "event-driven", "architecture", "distributed-systems"] } ]