Events
Events are messages that flow through your agent during execution, providing visibility into what's happening and enabling reactive behavior.
MindedJS currently supports 6 main event types. Each event type has its own specific input structure, output requirements, and use cases.
History Structure
All events provide access to the agent's history, which is a crucial part of understanding and tracking the execution flow. The history is an array of HistoryStep
objects that represent each step the agent has taken during execution.
HistoryStep Structure
Each history step contains the following information:
step
: Sequential step number in the agent's execution flowtype
: Type of the step (e.g., TRIGGER_NODE, APP_TRIGGER_NODE, TOOL_NODE, LLM_NODE)nodeId
: ID of the node that was executednodeDisplayName
: Human-readable name of the noderaw
: Raw data associated with the step (e.g., trigger input, tool output)messageIds
: IDs of messages associated with this step
Additional fields are available depending on the step type:
For
APP_TRIGGER_NODE
steps:appName
identifies the source applicationFor
TOOL_NODE
steps: Contains tool input and output information
Example Usage
agent.on(events.AI_MESSAGE, async ({ message, state }) => {
// Access the complete execution history
const history = state.history;
// Find the initial trigger that started this conversation
const triggerStep = history.find((step) => step.type === 'TRIGGER_NODE' || step.type === 'APP_TRIGGER_NODE');
// Find all tool executions in this conversation
const toolSteps = history.filter((step) => step.type === 'TOOL_NODE');
// Get the last executed node
const lastStep = history[history.length - 1];
console.log(`Conversation started with trigger: ${triggerStep?.nodeDisplayName}`);
console.log(`Used ${toolSteps.length} tools so far`);
console.log(`Last executed node: ${lastStep?.nodeDisplayName}`);
});
INIT
The INIT
event is emitted when the agent's graph state is initialized. This happens when a new session begins or when the agent starts processing a new conversation context.
Input Structure
{
state: { // Full initial agent state
messages: BaseMessage[]; // Empty array - no messages yet
memory: Memory; // Initial memory state (from your schema defaults)
history: HistoryStep[]; // Empty array - no flow history yet
sessionId: string; // Session identifier (generated or provided)
sessionType: SessionType; // Type of session (TEXT, VOICE, etc.)
}
}
Handler Return Value
Return type:
void
Purpose: Handlers are used for side effects like logging, setup, or initialization tasks
Note: Return values are ignored
Usage Example
import { Agent, events } from 'mindedjs';
const agent = new Agent({
memorySchema,
config,
tools,
});
// Listen to initialization events
agent.on(events.INIT, async ({ state }) => {
console.log('Agent initialized for session:', state.sessionId);
console.log('Session type:', state.sessionType);
console.log('Initial memory:', state.memory);
// Setup session-specific resources
await initializeSessionResources(state.sessionId);
// Log session start for analytics
await logSessionStart({
sessionId: state.sessionId,
sessionType: state.sessionType,
timestamp: new Date(),
});
// Initialize external services if needed
if (state.sessionType === 'VOICE') {
await setupVoiceSession(state.sessionId);
}
});
Common Use Cases
Session Logging: Track when new sessions begin for analytics
Resource Initialization: Set up session-specific resources or connections
State Validation: Verify initial memory state meets requirements
External Service Setup: Initialize third-party services for the session
Session Routing: Route sessions to appropriate handlers based on type
Debugging: Log initial state for troubleshooting
AI_MESSAGE
The AI_MESSAGE
event is emitted when an AI generates a message that should be sent to the user.
Input Structure
{
message: string; // The AI-generated message content
state: { // Full agent state
messages: BaseMessage[]; // Conversation messages
memory: Memory; // Current memory state (your defined memory schema)
history: HistoryStep[]; // Flow execution history with detailed step information
sessionId: string; // Session identifier
}
}
Handler Return Value
Return type:
void
Purpose: Handlers are used for side effects like sending messages to UI
Note: Return values are ignored
Usage Example
import { Agent, events } from 'mindedjs';
const agent = new Agent({
memorySchema,
config,
tools,
});
// Listen to AI messages
agent.on(events.AI_MESSAGE, async ({ message, state }) => {
console.log('AI said:', message);
console.log('Current memory:', state.memory);
console.log('Session ID:', state.sessionId);
console.log('Message count:', state.messages.length);
// Send message to user interface with session context
await sendMessageToUser(message, state.sessionId);
// Send via WebSocket with session information
await websocket.send(
JSON.stringify({
type: 'ai_message',
content: message,
sessionId: state.sessionId,
memory: state.memory,
}),
);
});
Common Use Cases
Real-time Chat UI: Send AI responses to chat interfaces with session context
Logging: Record AI responses for analytics or debugging with session tracking
Message Formatting: Transform AI messages before displaying to users
Notifications: Trigger alerts or notifications based on AI responses
Session Management: Route messages to specific user sessions or conversation threads
TRIGGER_EVENT
The TRIGGER_EVENT
event is emitted when a trigger node is executed. This event allows you to qualify, transform, and provide initial state for trigger inputs before they're processed by the agent.
Input Structure
{
triggerName: string; // Name of the trigger being executed
triggerBody: any; // The trigger input data (type varies by trigger)
sessionId?: string; // Optional session ID for the trigger execution
}
Handler Return Values
TRIGGER_EVENT handlers must return an object that contains, at minimum, an isQualified: boolean
field. Depending on your needs you may also return messages
, memory
, or a sessionId
.
The three common patterns are:
1. Provide Initial State & Qualify
{
isQualified: true, // ✅ The trigger should be processed
messages?: BaseMessage[], // Optional initial conversation messages
memory?: Memory, // Optional initial memory state
history?: HistoryStep[], // Optional history steps to include
sessionId?: string, // Optional session continuity identifier
state?: {
goto?: string, // Optional: jump to a specific node ID
}
}
2. Disqualify the Trigger
{
isQualified: false; // ❌ Rejects / disqualifies the trigger
}
3. Qualify Without Extra State
{
isQualified: true; // ✅ Accept the trigger – no extra state needed
}
Note on sessionId: The sessionId
is crucial for persistence and resuming existing sessions. When you provide a sessionId
that already exists, the agent will resume from the previous state. If none is provided or a new one is given, a fresh execution starts. The platform will automatically generate a sessionId
for you in the sandbox playground – make sure to pass it forward in that environment.
Usage Examples
Processing User Input
agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, sessionId }) => {
if (triggerName === 'userMessage') {
console.log('Processing trigger for session:', sessionId);
return {
isQualified: true,
memory: {
conversationStarted: true,
sessionId: sessionId, // Store session ID in memory if needed
},
messages: [new HumanMessage(triggerBody)],
};
}
});
Trigger Qualification
agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
// Validate the trigger input
if (!isValidInput(triggerBody)) {
return { isQualified: false }; // Disqualify the trigger
}
// Only process during business hours
if (triggerName === 'supportRequest' && !isBusinessHours()) {
return { isQualified: false };
}
return {
isQualified: true,
memory: { validatedInput: triggerBody },
messages: [],
};
});
Input Transformation
agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody }) => {
if (triggerName === 'emailTrigger') {
// Transform email data into structured format
const parsedEmail = parseEmailContent(triggerBody);
return {
isQualified: true,
memory: {
emailSubject: parsedEmail.subject,
senderEmail: parsedEmail.from,
},
messages: [new HumanMessage(parsedEmail.content)],
};
}
// Disqualify all other triggers handled by this listener
return { isQualified: false };
});
Dynamic Flow Control with goto
agent.on(events.TRIGGER_EVENT, async ({ triggerName, triggerBody, state }) => {
// Check condition and jump to specific node
if (triggerBody.priority === 'high') {
return {
isQualified: true,
state: {
...state,
goto: 'high-priority-handler', // Jump to specific node
},
};
}
return { isQualified: true };
});
Note: The jump occurs only when the current invocation completes and the next one begins. The agent will finish executing the current node before jumping to the specified node.
Common Use Cases
Input Validation: Ensure trigger data meets requirements before processing
Data Transformation: Convert trigger inputs into standardized formats
Context Setting: Provide initial memory state based on trigger context
Access Control: Disqualify triggers based on permissions or business rules
Routing Logic: Handle different trigger types with specific logic
ERROR
The ERROR
event is emitted when an error occurs during agent execution. This event allows you to handle errors gracefully, log them for debugging, implement custom error recovery logic, or control whether the error should be thrown onwards.
Input Structure
{
error: Error; // The error object that was thrown
state: { // Full agent state at the time of error
messages: BaseMessage[]; // Conversation messages
memory: Memory; // Current memory state (your defined memory schema)
history: HistoryStep[]; // Flow execution history with detailed step information
sessionId: string; // Session identifier
}
}
Handler Return Value
{
throwError: boolean; // Whether to throw the error onwards and stop the agent run
state?: Partial<State<Memory>>; // Optional state updates to apply
}
throwError: When set to
true
, the error will be thrown onwards and the agent run will stop. Iffalse
or not returned, the error is caught and the agent continues.state: Optional partial state updates to apply before continuing or throwing
Usage Example
import { Agent, events } from 'mindedjs';
const agent = new Agent({
memorySchema,
config,
tools,
});
// Listen to errors and control error flow
agent.on(events.ERROR, async ({ error, state }) => {
console.error('Agent error occurred:', error.message);
console.error('Error stack:', error.stack);
console.log('Session ID:', state.sessionId);
console.log('Current memory:', state.memory);
// Log to external service
await logger.error({
message: 'Agent execution error',
error: error.message,
stack: error.stack,
sessionId: state.sessionId,
memory: state.memory,
});
// Handle recoverable vs non-recoverable errors
if (error.message.includes('rate limit')) {
// Recoverable error - update state and continue
return {
throwError: false, // Don't stop the agent
state: {
memory: {
...state.memory,
errorRecovered: true,
lastError: error.message,
},
},
};
}
// Critical error - stop the agent
if (error.message.includes('authentication failed')) {
await notificationService.alert({
type: 'critical_error',
error: error.message,
sessionId: state.sessionId,
});
return {
throwError: true, // Stop the agent run
};
}
// Default: let the error be handled normally
return { throwError: false };
});
Common Use Cases
Error Logging: Record errors for debugging and monitoring with full context
Error Recovery: Implement custom recovery logic by returning
throwError: false
and updating stateCritical Error Handling: Stop agent execution for unrecoverable errors with
throwError: true
User Notifications: Provide graceful error messages to users
Monitoring & Alerting: Integrate with monitoring systems for error tracking
Session Management: Clean up or reset sessions that encountered errors
Analytics: Track error patterns and frequencies for system improvement
Graceful Degradation: Continue execution with fallback behavior for non-critical errors
ON_LOGICAL_CONDITION
The ON_LOGICAL_CONDITION
event is emitted when the agent is about to evaluate a logical condition on an edge. This event provides visibility into the condition evaluation process and allows you to track which conditions are being checked during flow execution.
Input Structure
{
edge: LogicalConditionEdge; // The edge containing the condition
state: { // Full agent state at evaluation time
messages: BaseMessage[]; // Conversation messages
memory: Memory; // Current memory state (your defined memory schema)
history: HistoryStep[]; // Flow execution history with detailed step information
sessionId: string; // Session identifier
};
condition: string; // The condition expression being evaluated
}
Handler Return Value
Return type:
void
Purpose: Handlers are used for debugging, logging, and monitoring condition evaluations
Note: Return values are ignored
Usage Example
import { Agent, events } from 'mindedjs';
const agent = new Agent({
memorySchema,
config,
tools,
});
// Listen to condition evaluation events
agent.on(events.ON_LOGICAL_CONDITION, async ({ edge, state, condition }) => {
console.log('Evaluating condition:', condition);
console.log('On edge from:', edge.source, 'to:', edge.target);
console.log('Current memory:', state.memory);
console.log('Session ID:', state.sessionId);
// Log for debugging
await logger.debug({
event: 'condition_evaluation_start',
condition,
edge: {
source: edge.source,
target: edge.target,
},
memory: state.memory,
sessionId: state.sessionId,
});
// Track condition usage analytics
await analytics.track('condition_evaluated', {
condition,
edgeSource: edge.source,
edgeTarget: edge.target,
sessionId: state.sessionId,
});
});
Common Use Cases
Debugging Flow Logic: Trace which conditions are evaluated and in what order
Performance Monitoring: Track when condition evaluations start
Analytics: Understand which flow paths are most commonly evaluated
Testing: Verify that expected conditions are being checked
Audit Logging: Record decision points for compliance or debugging
ON_LOGICAL_CONDITION_RESULT
The ON_LOGICAL_CONDITION_RESULT
event is emitted after a logical condition has been evaluated, providing the result and execution metrics. This event is crucial for understanding flow decisions and monitoring performance.
Input Structure
{
edge: LogicalConditionEdge; // The edge containing the condition
state: { // Full agent state after evaluation
messages: BaseMessage[]; // Conversation messages
memory: Memory; // Current memory state (your defined memory schema)
history: HistoryStep[]; // Flow execution history with detailed step information
sessionId: string; // Session identifier
};
condition: string; // The condition expression that was evaluated
result: boolean; // The evaluation result (true/false)
executionTimeMs: number; // Time taken to evaluate the condition in milliseconds
error?: Error; // Optional error if evaluation failed
}
Handler Return Value
Return type:
void
Purpose: Handlers are used for logging results, performance monitoring, and debugging
Note: Return values are ignored
Usage Example
import { Agent, events } from 'mindedjs';
const agent = new Agent({
memorySchema,
config,
tools,
});
// Listen to condition results
agent.on(events.ON_LOGICAL_CONDITION_RESULT, async ({ edge, state, condition, result, executionTimeMs, error }) => {
console.log('Condition result:', result);
console.log('Execution time:', executionTimeMs, 'ms');
if (error) {
console.error('Condition evaluation failed:', error.message);
}
// Log detailed results
await logger.debug({
event: 'condition_evaluation_complete',
condition,
result,
executionTimeMs,
edge: {
source: edge.source,
target: edge.target,
},
memory: state.memory,
sessionId: state.sessionId,
error: error?.message,
});
// Performance monitoring
if (executionTimeMs > 10) {
await logger.warn({
message: 'Slow condition detected',
condition,
executionTimeMs,
sessionId: state.sessionId,
});
}
// Track failed conditions
if (!result) {
await analytics.track('condition_failed', {
condition,
edgeSource: edge.source,
edgeTarget: edge.target,
sessionId: state.sessionId,
});
}
});
Common Use Cases
Performance Monitoring: Track execution times to identify slow conditions
Debugging Failed Conditions: Understand why certain flow paths aren't taken
Flow Analytics: Analyze which conditions pass/fail most frequently
Error Tracking: Monitor and alert on condition evaluation errors
Optimization: Identify conditions that could be simplified or cached
Testing: Verify condition results match expected behavior
Last updated