Murmuration (3.0.0)

A powerful and flexible AI agent framework for building intelligent applications with support for multiple LLM providers and tool chaining. Murmuration provides type-safe, thread-safe, and reliable systems for agent coordination, state management, and function execution.

GitHub Repository Tutorials

⚠️ WARNING

If you plan to use this in production, ensure you have proper error handling and testing in place as interaction with AI models can be unpredictable.

About Murmuration

The name "Murmuration" is inspired by the mesmerizing flocking behavior of birds, symbolizing the framework's focus on coordinated agent interactions and dynamic workflows. 🐦💫

What's New in Murmuration 3.0.0 🐦

Breaking Changes

This version includes significant changes that may require updates to your implementation. Please refer to the Migration Guide for detailed steps to upgrade smoothly.

Table of Contents 📚

Overview 🔍

Murmuration offers:

Installation ⚙️

Add to your pubspec.yaml:

dependencies:
  murmuration: ^3.0.0

Then run:

dart pub get

Core Features 🛠️

Configuration

final config = MurmurationConfig(
  provider: LLMProvider.openAI,  // Choose from OpenAI, Google, or Anthropic
  apiKey: 'your-api-key',
  model: 'gpt-4-turbo-preview',  // Model specific to the chosen provider
  debug: true,                    // Enable debug mode for verbose logging
  stream: false,                  // Disable streaming by default
  logger: MurmurationLogger(enabled: true),  // Enable logging
  timeout: Duration(seconds: 30),  // Set request timeout
  maxRetries: 3,                 // Number of retry attempts
  retryDelay: Duration(seconds: 1),  // Delay between retries
  enableCache: true,             // Enable response caching
  cacheTimeout: Duration(hours: 1),  // Cache expiration time
  rateLimit: RateLimit(          // Rate limiting configuration
    requestsPerMinute: 60,
    maxConcurrentRequests: 5
  )
);

Error Handling

try {
  final result = await agent.execute("Process data");
} on MurmurationException catch (e) {
  print('Error: ${e.message}');  // Human-readable error message
  print('Original error: ${e.originalError}');  // Original exception
  print('Stack trace: ${e.stackTrace}');  // Full stack trace
}

Logging

final logger = MurmurationLogger(
  enabled: true,
  onLog: (message) => print('Log: $message'),  // Log handler
  onError: (message, error, stackTrace) {      // Error handler
    print('Error: $message');
    print('Details: $error');
  }
);

Usage Guide 📖

Basic Usage

void main() async {
  final murmur = Murmuration(config);

  final agent = await murmur.createAgent(
    {'role': 'Assistant', 'context': 'Data processing'},
    currentAgentIndex: 1,
    totalAgents: 1
  );

  final result = await agent.execute("Process this data");
  print(result.output);
}

Advanced Usage

Custom Schema Fields

class DateTimeSchemaField extends SchemaField {
  final DateTime? minDate;
  final DateTime? maxDate;

  const DateTimeSchemaField({
    required String description,
    this.minDate,
    this.maxDate,
    bool required = true,
  }) : super(
    description: description,
    required: required,
  );

  @override
  bool isValidType(Object? value) =>
    value == null ||
    value is DateTime ||
    (value is String && DateTime.tryParse(value) != null);

  @override
  bool validate(DateTime? value) {
    if (value == null) return !required;
    if (minDate != null && value.isBefore(minDate!)) return false;
    if (maxDate != null && value.isAfter(maxDate!)) return false;
    return true;
  }

  @override
  DateTime? convert(Object? value) {
    if (value == null) return null;
    if (value is DateTime) return value;
    if (value is String) return DateTime.tryParse(value);
    return null;
  }
}

// Usage example:
final schema = OutputSchema(
  fields: {
    'name': StringSchemaField(
      description: 'User  name',
      minLength: 2,
      required: true
    ),
    'birthDate': DateTimeSchemaField(
      description: 'Birth date',
      minDate: DateTime(1900),
      maxDate: DateTime.now(),
      required: true
    )
  }
);

Streaming Responses 🌊

final config = MurmurationConfig(
  apiKey: 'your-api-key',
  stream: true,  // Enable streaming
  onStreamProgress: (progress) {  // Track streaming progress
    print('Progress: ${progress.percentage}%');
    print('Tokens received: ${progress.tokensReceived}');
    print('Time elapsed: ${progress.timeElapsed}');
  }
);

final agent = await murmur.createAgent({'role': 'Assistant'});
final result = await agent.execute("Generate a long story");

if (result.stream != null) {
  await for (final chunk in result.stream!) {
    print(chunk);  // Process each chunk as it arrives
  }
  
  // Access streaming statistics
  print('Total tokens: ${result.streamStats.totalTokens}');
  print('Stream duration: ${result.streamStats.duration}');
}

Agent Chains ⛓️

final result = await murmur.runAgentChain(
  input: documentText,
  agentInstructions: [
    {'role': 'Document Parser'},
    {'role': 'Data Analyzer'},
    {'role': 'Report Generator'}
  ],
  tools: [
    Tool(
      name: 'document_parser',
      description: 'Parses document text',
      parameters: {'text': StringSchemaField(description: 'Document text')},
      execute: (params) async => parseDocument(params['text'])
    )
  ],
  functions: {
    'analyze': (params) async => analyzeData(params),
    'generate_report': (params) async => generateReport(params)
  },
  logProgress: true,
  onProgress: (progress) {
    print('Progress: ${progress.currentAgent}/${progress.totalAgents}');
    print('Status: ${progress.status}');
  }
);

print('Final report: ${result.finalOutput}');

Core Systems 🔧

1. Message History

final history = MessageHistory(
  threadId: 'user-123',       // Unique thread identifier
  maxMessages: 50,            // Maximum messages to retain
  maxTokens: 4000             // Maximum total tokens
);

await history.addMessage(Message(
  role: 'user',
  content: 'Hello!',
  timestamp: DateTime.now()
));

await history.save();    // Persist to storage
await history.load();    // Load from storage
await history.clear();   // Clear history

2. State Management

final state = ImmutableState()
  .copyWith({
    'user': {'name': 'John', 'age': 30},
    'preferences': {'theme': 'dark'}
  });

final userName = state.get('user.name');  // Type-safe access

Real-World Examples 💡

Customer Support Bot

final supportBot = await murmur.createAgent({
  'role': 'Customer Support',
  'context': '''
    You are a helpful customer support agent.
    Follow company guidelines and maintain professional tone.
    Escalate sensitive issues to human support.
  '''
});

// Add ticket management tool
supportBot.addTool(Tool(
  name: 'create_ticket',
  description: 'Creates support ticket',
  parameters: {
    'priority': StringSchemaField(
      description: 'Ticket priority',
      enumValues: ['low', 'medium', 'high']
    ),
    'category': StringSchemaField(description: 'Issue category')
  },
  execute: (params) async => createSupportTicket(params)
));

final response = await supportBot.execute(userQuery);

Data Processing Pipeline

final pipeline = await murmur.runAgentChain(
  input: rawData,
  agentInstructions: [
    {'role': 'Data Validator'},
    {'role': 'Data Transformer'},
    {'role': 'Data Analyzer'},
    {'role': 'Report Generator'}
  ],
  tools: [
    Tool(
      name: 'data_validation',
      description: 'Validates data format',
      execute: validateData
    ),
    Tool(
      name: 'data_transform',
      description: 'Transforms data format',
      execute: transformData
    )
  ]
);

Troubleshooting 🔍

Common Issues

Timeout Errors

// Increase timeout duration
final config = MurmurationConfig(
  timeout: Duration(minutes: 2),
  maxRetries: 5
);

Memory Issues

// Manage message history
final config = MurmurationConfig(
  maxMessages: 30,
  maxTokens: 2000
);

State Management Issues

// Use proper state copying
final newState = state.copyWith(newData);
// Don't modify state directly
state._data['key'] = value;  // Wrong!

Best Practices 🏆

  1. Error Handling
    • Always wrap agent execution in try-catch blocks
    • Implement proper retry mechanisms
    • Log errors comprehensively
    • Handle timeouts appropriately
  2. Performance
    • Enable caching for repetitive tasks
    • Implement cleanup mechanisms
    • Monitor memory usage
    • Use appropriate timeout values
  3. Security
    • Validate all inputs
    • Handle sensitive data carefully
    • Implement proper access controls
    • Monitor API usage
  4. Message History
    • Set appropriate message limits
    • Implement cleanup policies
    • Handle thread IDs carefully
    • Monitor storage usage

Contributing 🤝

Guidelines for contributing to Murmuration:

  1. Fork the repository
  2. Create a feature branch
  3. Implement your changes
  4. Add tests
  5. Submit a pull request

Please ensure your code:

License 📜

This project is licensed under the MIT License - see the LICENSE file for details.

Author ✍️

This project is authored and maintained by Agniva Maiti.