murmuration 1.0.0
murmuration: ^1.0.0 copied to clipboard
A framework for multi-agent orchestration in Dart (Flutter).
[Murmuration Logo]
Murmuration (1.0.0) π¦β¨ #
[Murmuration]](https://agnivamaiti.github.io/murmuration/) is a Dart framework designed for orchestrating multi-agent interactions using Google's Generative AI models. It aims to facilitate seamless agent coordination and function execution, providing an ergonomic interface for constructing complex AI workflows.
[β οΈ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.
The name "Murmuration" is inspired by the mesmerizing flocking behavior of birds, symbolizing the framework's focus on coordinated agent interactions and dynamic workflows. π¦π«
Table of Contents π #
- Installation
- Quick Start
- Key Features
- Core Concepts
- Progress Tracking
- Streaming Support
- Debugging
- Error Handling
- API Reference
- Best Practices
- Examples
- Contributing
- License
Installation βοΈ #
Add to your pubspec.yaml:
dependencies:
murmuration: ^latest_version
google_generative_ai: ^latest_version
Then run:
dart pub get
Quick Start π #
import 'package:murmuration/murmuration.dart';
import 'package:google_generative_ai/google_generative_ai.dart';
void main() async {
final config = MurmurationConfig(
apiKey: 'your-api-key',
model: 'gemini-1.5-flash-latest',
debug: false,
stream: false,
logger: MurmurationLogger()
);
final murmur = Murmuration(config);
final result = await murmur.run(
input: "Hello!",
agentInstructions: {
'role': 'You are a helpful assistant.'
},
stateVariables: {}, // Optional initial state
tools: [], // Optional tools
functions: {}, // Optional function handlers
onProgress: null // Optional progress callback
);
print(result.output);
}
Why Murmuration? π€ #
Murmuration is designed for situations where you need:
- Multiple specialized agents working together π€
- Complex function calling and tool usage with specific response formats π§
- State management and context preservation across agent interactions π
- Detailed progress tracking and logging π
- Real-time streaming of responses with configurable delay β³
- Integration with Google's Generative AI models π
Key Features π #
- Streamlined Agent Management: Create and coordinate multiple agents with distinct roles and capabilities
- Function Registration: Register custom functions with specific parameter types that agents can invoke
- Tool Integration: Add specialized tools with defined schemas for agent use
- State Management: Built-in state handling for maintaining context across agent interactions
- Progress Tracking: Detailed progress monitoring with timestamps and status updates
- Streaming Support: Real-time streaming of agent responses with configurable delays
- Agent Chains: Sequential execution of multiple agents with automatic state handoff
Core Concepts π§ #
Agents #
Agents are the fundamental building blocks in Murmuration. Each agent is powered by Google's GenerativeModel and encapsulates:
- Instructions defining its behavior
- Available tools and functions
- State management capabilities
- Progress reporting mechanisms
final agent = murmur.createAgent(
{'role': 'You analyze data and provide insights.'},
currentAgentIndex: 1, // Optional: for chain positioning
totalAgents: 1, // Optional: total agents in chain
onProgress: (progress) { // Optional: progress tracking
print(progress.toString());
}
);
// Registering a function with proper type annotation
agent.registerFunction(
'analyzeData',
(Map<String, dynamic> params) {
// Analyze data logic here
return 'Analysis complete';
}
);
Function Handlers and Response Format #
Functions must follow a specific format for registration and invocation. The Agent class detects function calls by searching for the text "function:" in the model's response:
// Function handler type definition
typedef FunctionHandler = dynamic Function(Map<String, dynamic>);
// Registering a function
void registerDataFunction(Agent agent) {
agent.registerFunction('processData', (Map<String, dynamic> params) {
// Access context variables if available
final contextVars = params['context_variables'];
// Process data
return {'result': 'Processed data'};
});
}
// Function call format in agent responses ```dart
// The agent must return text in this EXACT format:
// function: functionName(param1: value1, param2: value2)
// Note: The format must match exactly, including spaces after colons
Tools π οΈ #
Tools must be defined with complete schemas and type-safe execution functions:
final dataTool = Tool(
name: 'data_processor',
description: 'Processes raw data into structured format',
schema: {
'type': 'object',
'properties': {
'data': {'type': 'string'},
'format': {'type': 'string'}
}
},
execute: (Map<String, dynamic> params) {
// Tool execution logic
return 'Processed result';
}
);
agent.registerTool(dataTool);
Agent Chains and State Management π #
Create sequences of agents with state handoff. Note that the handoff method only copies state variables and doesn't transfer other agent properties:
final result = await murmur.runAgentChain(
input: "Analyze this data",
agentInstructions: [
{'role': 'You clean and prepare data'},
{'role': 'You analyze prepared data'},
{'role': 'You create summaries of analysis'}
],
tools: [], // Optional tools shared across chain
functions: {}, // Optional functions shared across chain
logProgress: true, // Enable progress logging
onProgress: (progress) { // Optional progress callback
print(progress.toString());
}
);
// Access chain results
print(result.finalOutput); // Final chain output
print(result.results.length); // Number of agent results
print(result.progress.length); // Number of progress records
Progress Tracking π #
Progress tracking includes timestamps and detailed status information:
final result = await murmur.run(
input: "Process this task",
onProgress: (progress) {
print('Agent ${progress.currentAgent}/${progress.totalAgents}');
print('Status: ${progress.status}');
print('Output: ${progress.output}');
print('Time: ${progress.timestamp}');
}
);
Streaming Support π #
Enable real-time streaming with configurable delay. The streaming implementation uses GenerativeModel's response text, splitting it into chunks with a 50ms delay:
final config = MurmurationConfig(
apiKey: 'your-api-key',
stream: true, // Enable streaming
debug: true // Optional: enable debug logging
);
final murmur = Murmuration(config);
final result = await murmur.run(
input: "Stream this response",
onProgress: (progress) {
print('Streaming: ${progress.status}');
}
);
// Stream includes 50ms delay between chunks
// Chunks are created by splitting the response text on spaces
await for (final chunk in result.stream!) {
print(chunk);
}
Internal streaming implementation details:
- Uses StreamController to manage the stream
- Splits response text on spaces for chunk creation
- Adds artificial 50ms delay between chunks
- Reports progress for each chunk streamed
Debugging π #
Enable comprehensive debug logging:
final config = MurmurationConfig(
apiKey: 'your-api-key',
debug: true,
logger: MurmurationLogger(
enabled: true,
onLog: (message) {
print('LOG: $message');
},
onError: (message) {
print('ERROR: $message');
}
)
);
Error Handling β οΈ #
Comprehensive error handling with original error preservation:
try {
final result = await murmur.run(
input: "Process this",
agentInstructions: {'role': 'Assistant'}
);
// Check for stream availability
if (result.stream != null) {
await for (final chunk in result.stream!) {
// Handle streaming response
}
} else {
// Handle regular response
print(result.output);
}
} on MurmurationError catch (e) {
print('Murmuration Error: ${e.message}');
if (e.originalError != null) {
print('Original Error: ${e.originalError}');
}
} catch (e) {
print('Unexpected Error: $e');
}
API Reference π #
MurmurationConfig #
Configuration options for the Murmuration instance:
final config = MurmurationConfig(
apiKey: 'required-api-key',
model: 'gemini-1.5-flash-latest', // Default model
debug: false, // Default debug mode
stream: false, // Default streaming mode
logger: MurmurationLogger( // Optional logger
enabled: false,
onLog: null,
onError: null
)
);
Agent Functions #
Core agent manipulation methods:
registerFunction(String name, FunctionHandler handler): Add custom function handlersregisterTool(Tool tool): Add specialized toolsupdateState(Map<String, dynamic> newState): Modify agent statehandoff(Agent nextAgent): Transfer state variables to another agentexecute(String input): Run the agent with input
Result Types #
// Agent execution result
class AgentResult {
final String output;
final Map<String, dynamic> stateVariables;
final List<String> toolCalls;
final Stream<String>? stream;
final List<AgentProgress>? progress;
}
// Chain execution result
class ChainResult {
final List<AgentResult> results;
final String finalOutput;
final List<AgentProgress> progress;
}
// Progress tracking information
class AgentProgress {
final int currentAgent;
final int totalAgents;
final String status;
final String? output;
final DateTime timestamp;
}
Best Practices π #
-
State Management
- Use immutable state operations with
updateState() - Clear state between chain executions
- Preserve context variables in state
- Remember that handoff only copies state variables
- Use immutable state operations with
-
Function Design
- Always use
Map<String, dynamic>for parameters - Follow the exact function call format in responses
- Handle missing or invalid parameters
- Test function call string parsing extensively
- Always use
-
Error Handling
- Catch
MurmurationErrorseparately - Preserve original errors
- Log errors through MurmurationLogger
- Handle GenerativeModel errors properly
- Catch
-
Progress Monitoring
- Implement
onProgresscallbacks - Track timing with timestamps
- Log state transitions
- Monitor streaming progress
- Implement
-
Tool Integration
- Define complete schemas
- Include parameter validation
- Document expected inputs/outputs
- Test tool execution thoroughly
-
Streaming
- Account for 50ms chunk delay
- Handle stream availability
- Implement proper stream cleanup
- Consider chunk size implications
Contributing π€ #
Guidelines for contributing to Murmuration:
- Fork the repository
- Create a feature branch
- Submit a pull request
Please ensure your code:
- Follows Dart conventions
- Is properly documented
- Handles errors appropriately
- Includes type annotations
License π #
This project is licensed under the MIT License - see the LICENSE file for details.
Author βοΈ #
This project is authored by Agniva Maiti.