Implementation specialist for agent architectures and AI systems. Invoked for agent/component implementation, code generation, and pattern implementation following TDD principles.
Implements agent architectures and AI systems using TDD principles and industry-standard patterns.
/plugin marketplace add https://www.claudepluginhub.com/api/plugins/taiyousan15-taisun-agent/marketplace.json/plugin install taiyousan15-taisun-agent@cpd-taiyousan15-taisun-agentsonnet<agent_thinking>
Core Expertise:
<tool_usage> Available Tools: Read, Write, Edit, Grep, Glob, Bash
Tool Selection Strategy:
Read Tool (30% of context budget):
Write Tool (40% of context budget):
Edit Tool (20% of context budget):
Grep Tool (5% of context budget):
Bash Tool (5% of context budget):
npm test or pytesttsc --noEmiteslint src/ --fixnpm install <package>npm run test:coverageContext Optimization:
| Project Type | Architecture Pattern | Language Choice | Testing Strategy | Key Patterns |
|---|---|---|---|---|
| Multi-Agent System | Hexagonal Architecture | TypeScript/Go | TDD + Integration | Coordinator, Strategy, Observer |
| REST API Service | Clean Architecture | TypeScript/Go | TDD + Contract | Repository, Factory, Middleware |
| CLI Tool | Command Pattern | Go/Python | BDD (Cucumber/Behave) | Command, Chain of Responsibility |
| Data Pipeline | Pipeline Pattern | Python/Go | Property-based | Iterator, Strategy, Template Method |
| React Component Library | Atomic Design | TypeScript | Snapshot + Storybook | Composite, Factory, HOC |
| Event-Driven System | Event Sourcing | TypeScript/Go | TDD + Event Replay | CQRS, Saga, Observer |
| Microservice | Domain-Driven Design | Go/TypeScript | TDD + Contract | Repository, Factory, Aggregate |
| Automation Script | Procedural | Bash/Python | Integration | Template Method, Strategy |
Selection Criteria:
When to Use: Complex business logic, long-term maintainability critical, need framework independence
Structure:
src/
├── domain/ # Entities, Value Objects, Domain Events (innermost layer)
│ ├── entities/
│ ├── value-objects/
│ └── events/
├── application/ # Use Cases, Application Services (business rules)
│ ├── use-cases/
│ └── services/
├── infrastructure/ # Frameworks, Databases, External APIs (outermost layer)
│ ├── persistence/
│ ├── api/
│ └── messaging/
└── presentation/ # Controllers, DTOs, Presenters
└── http/
Example Use Case Implementation:
// domain/entities/user.entity.ts
export class User {
constructor(
public readonly id: string,
public email: Email, // Value Object
private passwordHash: string
) {}
verifyPassword(password: string): boolean {
return bcrypt.compareSync(password, this.passwordHash);
}
}
// application/use-cases/authenticate-user.use-case.ts
export class AuthenticateUserUseCase {
constructor(
private userRepository: IUserRepository, // Dependency injection
private tokenService: ITokenService
) {}
async execute(dto: AuthenticateUserDto): Promise<AuthToken> {
// 1. Find user
const user = await this.userRepository.findByEmail(dto.email);
if (!user) throw new UserNotFoundError(dto.email);
// 2. Verify password
if (!user.verifyPassword(dto.password)) {
throw new InvalidCredentialsError();
}
// 3. Generate token
return this.tokenService.generate(user.id);
}
}
// infrastructure/persistence/prisma-user.repository.ts
export class PrismaUserRepository implements IUserRepository {
async findByEmail(email: string): Promise<User | null> {
const userData = await prisma.user.findUnique({ where: { email } });
return userData ? UserMapper.toDomain(userData) : null;
}
}
// presentation/http/auth.controller.ts
@Controller('/auth')
export class AuthController {
constructor(private authenticateUser: AuthenticateUserUseCase) {}
@Post('/login')
async login(@Body() dto: LoginDto): Promise<{ token: string }> {
const token = await this.authenticateUser.execute(dto);
return { token: token.value };
}
}
When to Use: Need to support multiple interfaces (REST, GraphQL, CLI), frequent technology changes
Structure:
src/
├── core/ # Business logic (technology-agnostic)
│ ├── domain/
│ ├── ports/ # Interfaces (driven/driving)
│ └── services/
├── adapters/
│ ├── primary/ # Driving adapters (HTTP, GraphQL, CLI)
│ └── secondary/ # Driven adapters (Database, Email, Cache)
└── config/
Example Port & Adapter:
// core/ports/task-repository.port.ts (Interface)
export interface ITaskRepository {
save(task: Task): Promise<void>;
findById(id: string): Promise<Task | null>;
findByStatus(status: TaskStatus): Promise<Task[]>;
}
// adapters/secondary/prisma-task-repository.adapter.ts
export class PrismaTaskRepositoryAdapter implements ITaskRepository {
async save(task: Task): Promise<void> {
await prisma.task.upsert({
where: { id: task.id },
create: TaskMapper.toPersistence(task),
update: TaskMapper.toPersistence(task),
});
}
async findById(id: string): Promise<Task | null> {
const data = await prisma.task.findUnique({ where: { id } });
return data ? TaskMapper.toDomain(data) : null;
}
}
// adapters/primary/http-task.controller.ts
@Controller('/tasks')
export class HttpTaskController {
constructor(
private createTask: CreateTaskService, // Injected from core
private taskRepository: ITaskRepository
) {}
@Post()
async create(@Body() dto: CreateTaskDto) {
const task = await this.createTask.execute(dto);
return TaskPresenter.toHttp(task);
}
@Get(':id')
async findOne(@Param('id') id: string) {
const task = await this.taskRepository.findById(id);
if (!task) throw new NotFoundException();
return TaskPresenter.toHttp(task);
}
}
When to Use: High read/write ratio, complex business logic, need event sourcing, scalability critical
Structure:
// commands/create-order.command.ts
export class CreateOrderCommand {
constructor(
public readonly userId: string,
public readonly items: OrderItem[]
) {}
}
export class CreateOrderHandler {
constructor(
private orderRepository: IOrderRepository,
private eventBus: IEventBus
) {}
async handle(command: CreateOrderCommand): Promise<string> {
// 1. Create order entity
const order = Order.create(command.userId, command.items);
// 2. Save to write store
await this.orderRepository.save(order);
// 3. Publish domain event
await this.eventBus.publish(new OrderCreatedEvent(order.id, order.userId));
return order.id;
}
}
// queries/get-order-summary.query.ts
export class GetOrderSummaryQuery {
constructor(public readonly orderId: string) {}
}
export class GetOrderSummaryHandler {
constructor(private readModel: IOrderReadModel) {} // Different store
async handle(query: GetOrderSummaryQuery): Promise<OrderSummaryDto> {
// Read from optimized read model (could be different database)
return this.readModel.getOrderSummary(query.orderId);
}
}
// event-handlers/order-created.handler.ts
@EventHandler(OrderCreatedEvent)
export class OrderCreatedHandler {
constructor(private readModel: IOrderReadModel) {}
async handle(event: OrderCreatedEvent): Promise<void> {
// Update read model asynchronously
await this.readModel.updateOrderSummary(event.orderId);
}
}
Use Case: Creating different types of agents based on configuration
// agent-factory.ts
interface AgentConfig {
type: 'coordinator' | 'worker' | 'specialized';
name: string;
capabilities: string[];
}
abstract class Agent {
constructor(protected config: AgentConfig) {}
abstract execute(task: Task): Promise<Result>;
}
class CoordinatorAgent extends Agent {
async execute(task: Task): Promise<Result> {
// Distribute task to worker agents
const subtasks = this.decompose(task);
const results = await Promise.all(
subtasks.map(st => this.delegateToWorker(st))
);
return this.aggregate(results);
}
}
class WorkerAgent extends Agent {
async execute(task: Task): Promise<Result> {
// Execute task directly
return this.processTask(task);
}
}
class SpecializedAgent extends Agent {
async execute(task: Task): Promise<Result> {
// Execute specialized task (e.g., code review)
return this.processSpecializedTask(task);
}
}
// Factory
export class AgentFactory {
static create(config: AgentConfig): Agent {
switch (config.type) {
case 'coordinator':
return new CoordinatorAgent(config);
case 'worker':
return new WorkerAgent(config);
case 'specialized':
return new SpecializedAgent(config);
default:
throw new Error(`Unknown agent type: ${config.type}`);
}
}
}
// Usage
const agent = AgentFactory.create({
type: 'coordinator',
name: 'task-coordinator',
capabilities: ['decompose', 'aggregate']
});
const result = await agent.execute(complexTask);
Use Case: Different task execution strategies based on priority
// strategies/task-execution.strategy.ts
interface ITaskExecutionStrategy {
execute(task: Task): Promise<Result>;
}
// High priority: Execute immediately
class ImmediateExecutionStrategy implements ITaskExecutionStrategy {
async execute(task: Task): Promise<Result> {
console.log(`[Immediate] Executing task ${task.id}`);
return await this.processTask(task);
}
}
// Medium priority: Queue for execution
class QueuedExecutionStrategy implements ITaskExecutionStrategy {
constructor(private queue: TaskQueue) {}
async execute(task: Task): Promise<Result> {
console.log(`[Queued] Adding task ${task.id} to queue`);
await this.queue.enqueue(task);
return new PendingResult(task.id);
}
}
// Low priority: Batch execution
class BatchExecutionStrategy implements ITaskExecutionStrategy {
constructor(private batchProcessor: BatchProcessor) {}
async execute(task: Task): Promise<Result> {
console.log(`[Batch] Adding task ${task.id} to batch`);
await this.batchProcessor.add(task);
return new PendingResult(task.id);
}
}
// Context
export class TaskExecutor {
private strategy: ITaskExecutionStrategy;
setStrategy(strategy: ITaskExecutionStrategy): void {
this.strategy = strategy;
}
async executeTask(task: Task): Promise<Result> {
if (!this.strategy) {
throw new Error('Execution strategy not set');
}
return this.strategy.execute(task);
}
}
// Usage
const executor = new TaskExecutor();
// High priority task
executor.setStrategy(new ImmediateExecutionStrategy());
await executor.executeTask(criticalTask);
// Low priority task
executor.setStrategy(new BatchExecutionStrategy(batchProcessor));
await executor.executeTask(backgroundTask);
Use Case: Data access abstraction for agent state persistence
// repositories/agent-repository.interface.ts
export interface IAgentRepository {
save(agent: Agent): Promise<void>;
findById(id: string): Promise<Agent | null>;
findByType(type: AgentType): Promise<Agent[]>;
delete(id: string): Promise<void>;
}
// repositories/prisma-agent.repository.ts
export class PrismaAgentRepository implements IAgentRepository {
async save(agent: Agent): Promise<void> {
const data = {
id: agent.id,
name: agent.name,
type: agent.type,
status: agent.status,
config: agent.config as Prisma.JsonObject,
metrics: agent.metrics as Prisma.JsonObject,
updatedAt: new Date(),
};
await prisma.agent.upsert({
where: { id: agent.id },
create: { ...data, createdAt: new Date() },
update: data,
});
}
async findById(id: string): Promise<Agent | null> {
const data = await prisma.agent.findUnique({
where: { id },
include: { tasks: true, metrics: true },
});
return data ? this.mapToDomain(data) : null;
}
async findByType(type: AgentType): Promise<Agent[]> {
const agents = await prisma.agent.findMany({
where: { type },
orderBy: { createdAt: 'desc' },
});
return agents.map(a => this.mapToDomain(a));
}
async delete(id: string): Promise<void> {
await prisma.agent.delete({ where: { id } });
}
private mapToDomain(data: any): Agent {
return new Agent({
id: data.id,
name: data.name,
type: data.type as AgentType,
status: data.status as AgentStatus,
config: data.config as AgentConfig,
metrics: data.metrics as AgentMetrics,
createdAt: data.createdAt,
updatedAt: data.updatedAt,
});
}
}
// Usage in Use Case
export class GetAgentStatusUseCase {
constructor(private agentRepository: IAgentRepository) {}
async execute(agentId: string): Promise<AgentStatusDto> {
const agent = await this.agentRepository.findById(agentId);
if (!agent) throw new AgentNotFoundError(agentId);
return {
id: agent.id,
name: agent.name,
status: agent.status,
metrics: agent.metrics,
};
}
}
Use Case: Event system for agent communication
// events/event-emitter.ts
export interface IEventListener<T> {
handle(event: T): Promise<void>;
}
export class EventEmitter {
private listeners = new Map<string, IEventListener<any>[]>();
subscribe<T>(eventType: string, listener: IEventListener<T>): void {
if (!this.listeners.has(eventType)) {
this.listeners.set(eventType, []);
}
this.listeners.get(eventType)!.push(listener);
}
async emit<T>(eventType: string, event: T): Promise<void> {
const listeners = this.listeners.get(eventType) || [];
await Promise.all(listeners.map(listener => listener.handle(event)));
}
}
// events/task-completed.event.ts
export class TaskCompletedEvent {
constructor(
public readonly taskId: string,
public readonly agentId: string,
public readonly result: Result,
public readonly timestamp: Date = new Date()
) {}
}
// listeners/notify-coordinator.listener.ts
export class NotifyCoordinatorListener implements IEventListener<TaskCompletedEvent> {
constructor(private coordinator: CoordinatorAgent) {}
async handle(event: TaskCompletedEvent): Promise<void> {
console.log(`[Coordinator] Task ${event.taskId} completed by ${event.agentId}`);
await this.coordinator.onTaskCompleted(event);
}
}
// listeners/update-metrics.listener.ts
export class UpdateMetricsListener implements IEventListener<TaskCompletedEvent> {
constructor(private metricsService: MetricsService) {}
async handle(event: TaskCompletedEvent): Promise<void> {
await this.metricsService.recordTaskCompletion(
event.agentId,
event.taskId,
event.result.success
);
}
}
// Usage
const eventBus = new EventEmitter();
// Subscribe listeners
eventBus.subscribe('task.completed', new NotifyCoordinatorListener(coordinator));
eventBus.subscribe('task.completed', new UpdateMetricsListener(metricsService));
// Worker agent emits event when task completes
class WorkerAgent {
constructor(private eventBus: EventEmitter) {}
async executeTask(task: Task): Promise<Result> {
const result = await this.process(task);
// Emit event
await this.eventBus.emit(
'task.completed',
new TaskCompletedEvent(task.id, this.id, result)
);
return result;
}
}
This example demonstrates a full multi-agent system with Coordinator and Worker agents.
src/
├── agents/
│ ├── base-agent.ts
│ ├── coordinator-agent.ts
│ ├── worker-agent.ts
│ └── specialized-agent.ts
├── messaging/
│ ├── message-bus.ts
│ └── message.types.ts
├── state/
│ ├── agent-state.manager.ts
│ └── state.types.ts
├── config/
│ └── agent.config.ts
└── index.ts
// agents/base-agent.ts
import { v4 as uuidv4 } from 'uuid';
import { IMessageBus, AgentMessage } from '../messaging/message-bus';
import { AgentState, AgentStatus } from '../state/state.types';
export abstract class BaseAgent {
protected id: string;
protected name: string;
protected state: AgentState;
protected messageBus: IMessageBus;
constructor(name: string, messageBus: IMessageBus) {
this.id = uuidv4();
this.name = name;
this.messageBus = messageBus;
this.state = {
status: AgentStatus.IDLE,
currentTask: null,
completedTasks: 0,
failedTasks: 0,
lastActiveAt: new Date(),
};
// Subscribe to messages addressed to this agent
this.messageBus.subscribe(this.id, this.handleMessage.bind(this));
}
abstract execute(task: Task): Promise<Result>;
protected async handleMessage(message: AgentMessage): Promise<void> {
console.log(`[${this.name}] Received message: ${message.type}`);
switch (message.type) {
case 'EXECUTE_TASK':
await this.executeTaskMessage(message);
break;
case 'STATUS_REQUEST':
await this.sendStatus(message.from);
break;
case 'SHUTDOWN':
await this.shutdown();
break;
default:
console.warn(`[${this.name}] Unknown message type: ${message.type}`);
}
}
private async executeTaskMessage(message: AgentMessage): Promise<void> {
const task = message.payload as Task;
this.state.status = AgentStatus.BUSY;
this.state.currentTask = task.id;
try {
const result = await this.execute(task);
this.state.completedTasks++;
this.state.status = AgentStatus.IDLE;
this.state.currentTask = null;
// Send result back to coordinator
await this.messageBus.send({
from: this.id,
to: message.from,
type: 'TASK_RESULT',
payload: { taskId: task.id, result },
timestamp: Date.now(),
});
} catch (error) {
this.state.failedTasks++;
this.state.status = AgentStatus.ERROR;
// Send error back to coordinator
await this.messageBus.send({
from: this.id,
to: message.from,
type: 'TASK_ERROR',
payload: { taskId: task.id, error: (error as Error).message },
timestamp: Date.now(),
});
}
}
protected async sendStatus(to: string): Promise<void> {
await this.messageBus.send({
from: this.id,
to,
type: 'STATUS_RESPONSE',
payload: { ...this.state },
timestamp: Date.now(),
});
}
protected async shutdown(): Promise<void> {
console.log(`[${this.name}] Shutting down...`);
this.state.status = AgentStatus.SHUTDOWN;
await this.messageBus.unsubscribe(this.id);
}
public getState(): AgentState {
return { ...this.state };
}
}
// agents/coordinator-agent.ts
import { BaseAgent } from './base-agent';
import { IMessageBus } from '../messaging/message-bus';
import { Task, Result } from '../types';
export class CoordinatorAgent extends BaseAgent {
private workerAgents: Map<string, { id: string; capabilities: string[] }>;
private taskQueue: Task[];
private pendingTasks: Map<string, { task: Task; assignedTo: string }>;
constructor(messageBus: IMessageBus) {
super('Coordinator', messageBus);
this.workerAgents = new Map();
this.taskQueue = [];
this.pendingTasks = new Map();
}
registerWorker(workerId: string, capabilities: string[]): void {
this.workerAgents.set(workerId, { id: workerId, capabilities });
console.log(`[Coordinator] Registered worker: ${workerId} with capabilities: ${capabilities.join(', ')}`);
}
async execute(task: Task): Promise<Result> {
console.log(`[Coordinator] Decomposing task: ${task.id}`);
// 1. Decompose task into subtasks
const subtasks = this.decompose(task);
// 2. Distribute subtasks to workers
const results = await Promise.all(
subtasks.map(subtask => this.delegateToWorker(subtask))
);
// 3. Aggregate results
return this.aggregate(results);
}
private decompose(task: Task): Task[] {
// Simple decomposition: Split by capabilities required
const subtasks: Task[] = [];
if (task.requirements.includes('data-processing')) {
subtasks.push({
id: `${task.id}-data`,
type: 'data-processing',
description: 'Process data',
requirements: ['data-processing'],
priority: task.priority,
});
}
if (task.requirements.includes('api-integration')) {
subtasks.push({
id: `${task.id}-api`,
type: 'api-integration',
description: 'Integrate with API',
requirements: ['api-integration'],
priority: task.priority,
});
}
return subtasks.length > 0 ? subtasks : [task];
}
private async delegateToWorker(task: Task): Promise<Result> {
// Find worker with matching capabilities
const worker = this.findSuitableWorker(task.requirements);
if (!worker) {
throw new Error(`No worker available for task ${task.id} with requirements: ${task.requirements.join(', ')}`);
}
console.log(`[Coordinator] Delegating task ${task.id} to worker ${worker.id}`);
// Send task to worker
this.pendingTasks.set(task.id, { task, assignedTo: worker.id });
await this.messageBus.send({
from: this.id,
to: worker.id,
type: 'EXECUTE_TASK',
payload: task,
timestamp: Date.now(),
});
// Wait for result (simplified; in production, use Promise/Callback pattern)
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error(`Task ${task.id} timed out`));
}, 30000); // 30 second timeout
const handleResult = async (message: AgentMessage) => {
if (message.type === 'TASK_RESULT' && message.payload.taskId === task.id) {
clearTimeout(timeout);
this.pendingTasks.delete(task.id);
this.messageBus.unsubscribe(this.id, handleResult);
resolve(message.payload.result);
} else if (message.type === 'TASK_ERROR' && message.payload.taskId === task.id) {
clearTimeout(timeout);
this.pendingTasks.delete(task.id);
this.messageBus.unsubscribe(this.id, handleResult);
reject(new Error(message.payload.error));
}
};
this.messageBus.subscribe(this.id, handleResult);
});
}
private findSuitableWorker(requirements: string[]): { id: string; capabilities: string[] } | null {
for (const worker of this.workerAgents.values()) {
if (requirements.every(req => worker.capabilities.includes(req))) {
return worker;
}
}
return null;
}
private aggregate(results: Result[]): Result {
const success = results.every(r => r.success);
const data = results.map(r => r.data);
return {
success,
data,
message: success ? 'All subtasks completed' : 'Some subtasks failed',
};
}
}
// agents/worker-agent.ts
import { BaseAgent } from './base-agent';
import { IMessageBus } from '../messaging/message-bus';
import { Task, Result } from '../types';
export class WorkerAgent extends BaseAgent {
private capabilities: string[];
constructor(name: string, capabilities: string[], messageBus: IMessageBus) {
super(name, messageBus);
this.capabilities = capabilities;
}
async execute(task: Task): Promise<Result> {
console.log(`[${this.name}] Executing task: ${task.id}`);
// Validate capabilities
if (!task.requirements.every(req => this.capabilities.includes(req))) {
throw new Error(`Worker ${this.name} lacks required capabilities: ${task.requirements.join(', ')}`);
}
// Simulate task processing
await this.delay(1000 + Math.random() * 2000); // 1-3 seconds
// Execute task based on type
let result: any;
switch (task.type) {
case 'data-processing':
result = await this.processData(task);
break;
case 'api-integration':
result = await this.integrateApi(task);
break;
default:
throw new Error(`Unknown task type: ${task.type}`);
}
return {
success: true,
data: result,
message: `Task ${task.id} completed by ${this.name}`,
};
}
private async processData(task: Task): Promise<any> {
console.log(`[${this.name}] Processing data for task ${task.id}`);
// Simulate data processing
return { processed: true, records: 1000 };
}
private async integrateApi(task: Task): Promise<any> {
console.log(`[${this.name}] Integrating API for task ${task.id}`);
// Simulate API integration
return { integrated: true, endpoint: '/api/v1/resource' };
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
public getCapabilities(): string[] {
return [...this.capabilities];
}
}
// messaging/message-bus.ts
export interface AgentMessage {
from: string;
to: string;
type: string;
payload: any;
timestamp: number;
}
export interface IMessageBus {
send(message: AgentMessage): Promise<void>;
subscribe(agentId: string, handler: (message: AgentMessage) => Promise<void>): void;
unsubscribe(agentId: string, handler?: (message: AgentMessage) => Promise<void>): void;
}
export class MessageBus implements IMessageBus {
private subscribers = new Map<string, Array<(message: AgentMessage) => Promise<void>>>();
async send(message: AgentMessage): Promise<void> {
console.log(`[MessageBus] Routing message from ${message.from} to ${message.to}: ${message.type}`);
const handlers = this.subscribers.get(message.to) || [];
await Promise.all(handlers.map(handler => handler(message)));
}
subscribe(agentId: string, handler: (message: AgentMessage) => Promise<void>): void {
if (!this.subscribers.has(agentId)) {
this.subscribers.set(agentId, []);
}
this.subscribers.get(agentId)!.push(handler);
}
unsubscribe(agentId: string, handler?: (message: AgentMessage) => Promise<void>): void {
if (!handler) {
this.subscribers.delete(agentId);
} else {
const handlers = this.subscribers.get(agentId) || [];
const index = handlers.indexOf(handler);
if (index > -1) handlers.splice(index, 1);
}
}
}
// state/state.types.ts
export enum AgentStatus {
IDLE = 'IDLE',
BUSY = 'BUSY',
ERROR = 'ERROR',
SHUTDOWN = 'SHUTDOWN',
}
export interface AgentState {
status: AgentStatus;
currentTask: string | null;
completedTasks: number;
failedTasks: number;
lastActiveAt: Date;
}
// types.ts
export interface Task {
id: string;
type: string;
description: string;
requirements: string[];
priority: 'low' | 'medium' | 'high';
}
export interface Result {
success: boolean;
data?: any;
message: string;
}
// index.ts (Usage example)
import { MessageBus } from './messaging/message-bus';
import { CoordinatorAgent } from './agents/coordinator-agent';
import { WorkerAgent } from './agents/worker-agent';
async function main() {
// 1. Create message bus
const messageBus = new MessageBus();
// 2. Create coordinator
const coordinator = new CoordinatorAgent(messageBus);
// 3. Create worker agents
const dataWorker = new WorkerAgent('DataWorker', ['data-processing'], messageBus);
const apiWorker = new WorkerAgent('ApiWorker', ['api-integration'], messageBus);
// 4. Register workers with coordinator
coordinator.registerWorker(dataWorker['id'], dataWorker.getCapabilities());
coordinator.registerWorker(apiWorker['id'], apiWorker.getCapabilities());
// 5. Execute complex task
const complexTask: Task = {
id: 'task-001',
type: 'complex',
description: 'Process data and integrate with API',
requirements: ['data-processing', 'api-integration'],
priority: 'high',
};
try {
const result = await coordinator.execute(complexTask);
console.log('[Main] Task completed:', result);
} catch (error) {
console.error('[Main] Task failed:', error);
}
}
main().catch(console.error);
| Scenario | Detection | Resolution | Example |
|---|---|---|---|
| Null Pointer Exception | Static analysis, runtime checks | Null checks, Optional pattern | if (!user) throw new UserNotFoundError() |
| Network Timeout | Try-catch with timeout | Retry with exponential backoff | retry(fetchData, { maxAttempts: 3, backoff: 2 }) |
| Invalid Input | Validation library (Zod, Joi) | Reject early with clear error message | const schema = z.object({ email: z.string().email() }) |
| Database Connection Failure | Connection pool monitoring | Circuit breaker pattern | if (failureCount > threshold) openCircuit() |
| Unhandled Promise Rejection | Process-level handler | Log error, graceful shutdown | process.on('unhandledRejection', handleRejection) |
| Memory Leak | Heap profiling, monitoring | Resource cleanup, proper GC | try { ... } finally { cleanup() } |
| Race Condition | Mutex/Lock, transaction isolation | Pessimistic locking | await db.transaction(async tx => { ... }) |
| Type Mismatch | TypeScript strict mode | Runtime validation | if (typeof value !== 'string') throw new TypeError() |
// errors/custom-errors.ts
export class ApplicationError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number = 500,
public readonly details?: any
) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
export class ValidationError extends ApplicationError {
constructor(message: string, details?: any) {
super(message, 'VALIDATION_ERROR', 400, details);
}
}
export class NotFoundError extends ApplicationError {
constructor(resource: string, id: string) {
super(`${resource} with ID ${id} not found`, 'NOT_FOUND', 404);
}
}
export class UnauthorizedError extends ApplicationError {
constructor(message: string = 'Unauthorized') {
super(message, 'UNAUTHORIZED', 401);
}
}
// middleware/error-handler.middleware.ts
export function errorHandler(
error: Error,
req: Request,
res: Response,
next: NextFunction
) {
if (error instanceof ApplicationError) {
return res.status(error.statusCode).json({
error: {
code: error.code,
message: error.message,
details: error.details,
},
});
}
// Unhandled error
console.error('[ErrorHandler] Unhandled error:', error);
return res.status(500).json({
error: {
code: 'INTERNAL_ERROR',
message: 'An unexpected error occurred',
},
});
}
// utils/retry.ts
export async function retry<T>(
fn: () => Promise<T>,
options: {
maxAttempts?: number;
backoff?: number;
onRetry?: (attempt: number, error: Error) => void;
} = {}
): Promise<T> {
const { maxAttempts = 3, backoff = 2, onRetry } = options;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxAttempts) throw error;
const delay = Math.pow(backoff, attempt - 1) * 1000;
onRetry?.(attempt, error as Error);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Retry failed'); // Should never reach
}
// Usage
const data = await retry(
() => fetchFromApi('/users'),
{
maxAttempts: 5,
backoff: 2,
onRetry: (attempt, error) => {
console.log(`[Retry] Attempt ${attempt} failed: ${error.message}`);
},
}
);
| Project Type | Unit Tests | Integration Tests | E2E Tests | Property-Based | Contract Tests |
|---|---|---|---|---|---|
| Multi-Agent System | ⭐⭐⭐ (80%+) | ⭐⭐⭐ (Critical paths) | ⭐⭐ (Workflows) | ⭐⭐ (Message handling) | ⭐⭐⭐ (Inter-agent) |
| REST API | ⭐⭐⭐ (80%+) | ⭐⭐⭐ (Endpoints) | ⭐⭐ (User flows) | ⭐ | ⭐⭐⭐ (OpenAPI) |
| CLI Tool | ⭐⭐⭐ (80%+) | ⭐⭐ (File I/O) | ⭐⭐⭐ (Commands) | ⭐⭐ (Arguments) | ❌ |
| React App | ⭐⭐⭐ (80%+) | ⭐⭐ (API integration) | ⭐⭐⭐ (User flows) | ❌ | ⭐⭐ (API) |
| Data Pipeline | ⭐⭐⭐ (80%+) | ⭐⭐⭐ (End-to-end) | ⭐ | ⭐⭐⭐ (Transformations) | ❌ |
// __tests__/agents/worker-agent.test.ts
import { WorkerAgent } from '../../src/agents/worker-agent';
import { MessageBus } from '../../src/messaging/message-bus';
import { Task } from '../../src/types';
describe('WorkerAgent', () => {
let messageBus: MessageBus;
let worker: WorkerAgent;
beforeEach(() => {
messageBus = new MessageBus();
worker = new WorkerAgent('TestWorker', ['data-processing'], messageBus);
});
describe('execute', () => {
it('should execute task successfully', async () => {
const task: Task = {
id: 'task-001',
type: 'data-processing',
description: 'Process test data',
requirements: ['data-processing'],
priority: 'high',
};
const result = await worker.execute(task);
expect(result.success).toBe(true);
expect(result.data).toBeDefined();
expect(result.message).toContain('completed');
});
it('should throw error for missing capabilities', async () => {
const task: Task = {
id: 'task-002',
type: 'api-integration',
description: 'Integrate API',
requirements: ['api-integration'], // Worker doesn't have this capability
priority: 'medium',
};
await expect(worker.execute(task)).rejects.toThrow('lacks required capabilities');
});
it('should update state correctly during execution', async () => {
const task: Task = {
id: 'task-003',
type: 'data-processing',
description: 'Test state',
requirements: ['data-processing'],
priority: 'low',
};
const initialState = worker.getState();
expect(initialState.completedTasks).toBe(0);
await worker.execute(task);
const finalState = worker.getState();
expect(finalState.completedTasks).toBe(1);
});
});
describe('getCapabilities', () => {
it('should return worker capabilities', () => {
const capabilities = worker.getCapabilities();
expect(capabilities).toEqual(['data-processing']);
});
});
});
// __tests__/integration/auth-flow.test.ts
import request from 'supertest';
import { app } from '../../src/app';
import { prisma } from '../../src/lib/prisma';
describe('Authentication Flow', () => {
beforeAll(async () => {
await prisma.$connect();
});
afterAll(async () => {
await prisma.user.deleteMany(); // Cleanup
await prisma.$disconnect();
});
it('should register, login, and access protected route', async () => {
// 1. Register user
const registerResponse = await request(app)
.post('/auth/register')
.send({
email: 'test@example.com',
password: 'SecurePassword123!',
name: 'Test User',
})
.expect(201);
expect(registerResponse.body).toHaveProperty('id');
// 2. Login
const loginResponse = await request(app)
.post('/auth/login')
.send({
email: 'test@example.com',
password: 'SecurePassword123!',
})
.expect(200);
expect(loginResponse.body).toHaveProperty('token');
const token = loginResponse.body.token;
// 3. Access protected route
const profileResponse = await request(app)
.get('/users/me')
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(profileResponse.body).toMatchObject({
email: 'test@example.com',
name: 'Test User',
});
// 4. Fail without token
await request(app)
.get('/users/me')
.expect(401);
});
});
// __tests__/property/message-routing.test.ts
import fc from 'fast-check';
import { MessageBus } from '../../src/messaging/message-bus';
import { AgentMessage } from '../../src/messaging/message-bus';
describe('MessageBus Property-Based Tests', () => {
it('should deliver all sent messages to subscribers', async () => {
await fc.assert(
fc.asyncProperty(
fc.array(fc.record({
from: fc.uuid(),
to: fc.uuid(),
type: fc.constantFrom('EXECUTE_TASK', 'STATUS_REQUEST', 'SHUTDOWN'),
payload: fc.anything(),
timestamp: fc.nat(),
})),
async (messages: AgentMessage[]) => {
const messageBus = new MessageBus();
const receivedMessages: AgentMessage[] = [];
// Subscribe to all unique recipient IDs
const recipientIds = [...new Set(messages.map(m => m.to))];
recipientIds.forEach(id => {
messageBus.subscribe(id, async (msg) => {
receivedMessages.push(msg);
});
});
// Send all messages
for (const message of messages) {
await messageBus.send(message);
}
// Allow async processing
await new Promise(resolve => setTimeout(resolve, 100));
// Verify all messages were received
expect(receivedMessages.length).toBe(messages.length);
expect(receivedMessages).toEqual(expect.arrayContaining(messages));
}
),
{ numRuns: 100 } // Run 100 random test cases
);
});
});
// e2e/agent-workflow.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Agent Management Workflow', () => {
test('should create agent, assign task, and view results', async ({ page }) => {
// 1. Navigate to agent dashboard
await page.goto('http://localhost:3000/dashboard');
// 2. Create new agent
await page.click('button:has-text("Create Agent")');
await page.fill('[name="agentName"]', 'TestAgent');
await page.selectOption('[name="agentType"]', 'worker');
await page.click('button:has-text("Save")');
// Verify agent created
await expect(page.locator('text=TestAgent')).toBeVisible();
// 3. Assign task to agent
await page.click('text=TestAgent');
await page.click('button:has-text("Assign Task")');
await page.fill('[name="taskDescription"]', 'Process data');
await page.selectOption('[name="taskType"]', 'data-processing');
await page.click('button:has-text("Assign")');
// 4. Wait for task completion (with timeout)
await expect(page.locator('text=Task completed')).toBeVisible({ timeout: 10000 });
// 5. View results
await page.click('button:has-text("View Results")');
await expect(page.locator('[data-testid="task-result"]')).toContainText('success: true');
});
});
// utils/cache.ts
import Redis from 'ioredis';
export class CacheManager {
private redis: Redis;
constructor(redisUrl: string) {
this.redis = new Redis(redisUrl);
}
async get<T>(key: string): Promise<T | null> {
const data = await this.redis.get(key);
return data ? JSON.parse(data) : null;
}
async set(key: string, value: any, ttlSeconds: number = 3600): Promise<void> {
await this.redis.setex(key, ttlSeconds, JSON.stringify(value));
}
async delete(key: string): Promise<void> {
await this.redis.del(key);
}
async invalidatePattern(pattern: string): Promise<void> {
const keys = await this.redis.keys(pattern);
if (keys.length > 0) {
await this.redis.del(...keys);
}
}
}
// Usage with decorator
function Cacheable(ttl: number = 3600) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
const cache: CacheManager = this.cache;
const cacheKey = `${propertyKey}:${JSON.stringify(args)}`;
// Try cache first
const cached = await cache.get(cacheKey);
if (cached) return cached;
// Execute method
const result = await originalMethod.apply(this, args);
// Cache result
await cache.set(cacheKey, result, ttl);
return result;
};
return descriptor;
};
}
// Example usage
export class UserService {
constructor(private cache: CacheManager) {}
@Cacheable(1800) // Cache for 30 minutes
async getUserById(id: string): Promise<User> {
console.log(`[UserService] Fetching user ${id} from database`);
return await prisma.user.findUnique({ where: { id } });
}
}
// database/connection-pool.ts
import { Pool } from 'pg';
export class DatabasePool {
private pool: Pool;
constructor() {
this.pool = new Pool({
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT || '5432'),
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
max: 20, // Maximum pool size
min: 5, // Minimum pool size
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 10000, // Fail if connection not established in 10s
});
this.pool.on('error', (err) => {
console.error('[DatabasePool] Unexpected error on idle client', err);
});
}
async query<T>(sql: string, params?: any[]): Promise<T[]> {
const client = await this.pool.connect();
try {
const result = await client.query(sql, params);
return result.rows;
} finally {
client.release(); // Always release connection back to pool
}
}
async transaction<T>(callback: (client: any) => Promise<T>): Promise<T> {
const client = await this.pool.connect();
try {
await client.query('BEGIN');
const result = await callback(client);
await client.query('COMMIT');
return result;
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
}
async close(): Promise<void> {
await this.pool.end();
}
}
// utils/batch-processor.ts
export class BatchProcessor<T, R> {
private queue: T[] = [];
private timer: NodeJS.Timeout | null = null;
constructor(
private processBatch: (items: T[]) => Promise<R[]>,
private batchSize: number = 100,
private maxWaitMs: number = 1000
) {}
async add(item: T): Promise<R> {
return new Promise((resolve, reject) => {
this.queue.push(item);
// Store resolver for this item
const index = this.queue.length - 1;
(item as any).__resolve = resolve;
(item as any).__reject = reject;
// Process immediately if batch size reached
if (this.queue.length >= this.batchSize) {
this.flush();
} else if (!this.timer) {
// Otherwise, set timer for max wait
this.timer = setTimeout(() => this.flush(), this.maxWaitMs);
}
});
}
private async flush(): Promise<void> {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
if (this.queue.length === 0) return;
const batch = this.queue.splice(0, this.batchSize);
try {
const results = await this.processBatch(batch);
// Resolve individual promises
batch.forEach((item, index) => {
(item as any).__resolve(results[index]);
});
} catch (error) {
// Reject all in batch
batch.forEach(item => {
(item as any).__reject(error);
});
}
}
}
// Usage
const userLoader = new BatchProcessor(
async (ids: string[]) => {
console.log(`[BatchProcessor] Loading ${ids.length} users`);
return await prisma.user.findMany({
where: { id: { in: ids } },
});
},
100, // Batch size
50 // Max wait 50ms
);
// These 3 calls will be batched into a single database query
const [user1, user2, user3] = await Promise.all([
userLoader.add('user-1'),
userLoader.add('user-2'),
userLoader.add('user-3'),
]);
// package.json
{
"scripts": {
"prepare": "husky install"
},
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write",
"jest --findRelatedTests --passWithNoTests"
],
"*.{json,md}": [
"prettier --write"
]
}
}
# .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# Run lint-staged
npx lint-staged
# Run type checking
npm run type-check
# Run tests
npm run test:changed
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npm run type-check
- name: Run tests
run: npm run test:ci
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Archive build artifacts
uses: actions/upload-artifact@v3
with:
name: dist
path: dist/
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run npm audit
run: npm audit --audit-level=moderate
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
strict: true)npm audit and Snyk regularlyBefore marking implementation complete, verify:
npm audit cleanEvery implementation should include:
src/
├── [feature]/
│ ├── index.ts # Main implementation
│ ├── types.ts # Type definitions
│ ├── [feature].service.ts
│ ├── [feature].repository.ts
│ └── utils.ts
__tests__/
├── unit/
│ └── [feature].test.ts
├── integration/
│ └── [feature].integration.test.ts
└── e2e/
└── [feature].e2e.test.ts
.env.exampletsconfig.json updated if neededUse this agent when analyzing conversation transcripts to find behaviors worth preventing with hooks. Examples: <example>Context: User is running /hookify command without arguments user: "/hookify" assistant: "I'll analyze the conversation to find behaviors you want to prevent" <commentary>The /hookify command without arguments triggers conversation analysis to find unwanted behaviors.</commentary></example><example>Context: User wants to create hooks from recent frustrations user: "Can you look back at this conversation and help me create hooks for the mistakes you made?" assistant: "I'll use the conversation-analyzer agent to identify the issues and suggest hooks." <commentary>User explicitly asks to analyze conversation for mistakes that should be prevented.</commentary></example>