Adding Event Listeners
After initializing the Anam client, you can register event listeners using the addListener method:
import { AnamClient , AnamEvent } from "@anam-ai/js-sdk" ;
anamClient . addListener ( AnamEvent . CONNECTION_ESTABLISHED , () => {
console . log ( "Connection Established" );
});
anamClient . addListener ( AnamEvent . MESSAGE_HISTORY_UPDATED , ( messages ) => {
console . log ( "Updated Messages:" , messages );
});
Available Events
Event Name Description Callback Parameters CONNECTION_ESTABLISHEDFired when the WebRTC connection is established None CONNECTION_CLOSEDFired when the connection is terminated reason: ConnectionClosedCode, details?: stringSESSION_READYFired after the session initializes and backend components are ready sessionId: stringVIDEO_STREAM_STARTEDFired when the video stream becomes available videoStream: MediaStreamVIDEO_PLAY_STARTEDFired when the first video frames start playing None AUDIO_STREAM_STARTEDFired when the audio stream becomes available audioStream: MediaStreamINPUT_AUDIO_STREAM_STARTEDFired when microphone input is initialized audioStream: MediaStreamMESSAGE_HISTORY_UPDATEDFired when a participant finishes speaking with full history messages: Message[]MESSAGE_STREAM_EVENT_RECEIVEDFired with real-time transcription updates event: MessageStreamEventTALK_STREAM_INTERRUPTEDFired when a user interrupts a TalkMessageStream correlationId: stringTOOL_CALL_STARTEDFired when any tool call begins event: ToolCallStartedPayloadTOOL_CALL_COMPLETEDFired when a tool call completes successfully event: ToolCallCompletedPayloadTOOL_CALL_FAILEDFired when a tool call fails event: ToolCallFailedPayloadCLIENT_TOOL_EVENT_RECEIVEDDeprecated - Use TOOL_CALL_STARTED insteadevent: ClientToolEventSERVER_WARNINGFired when the server sends a warning message message: stringMIC_PERMISSION_PENDINGFired when microphone permission is being requested None MIC_PERMISSION_GRANTEDFired when microphone permission is granted None MIC_PERMISSION_DENIEDFired when microphone permission is denied error: stringINPUT_AUDIO_DEVICE_CHANGEDFired when the input audio device changes deviceId: stringREASONING_HISTORY_UPDATEDFired when reasoning/thought history is updated messages: ReasoningMessage[]REASONING_STREAM_EVENT_RECEIVEDFired with real-time reasoning updates event: ReasoningStreamEvent
Type Definitions
Message
interface Message {
id : string ;
content : string ;
role : MessageRole ; // 'user' | 'persona'
interrupted ?: boolean ;
}
MessageStreamEvent
interface MessageStreamEvent {
id : string ;
content : string ;
role : MessageRole ; // 'user' | 'persona'
endOfSpeech : boolean ;
interrupted : boolean ;
}
interface ToolCallStartedPayload {
eventUid : string ; // Unique ID for this event
toolCallId : string ; // ID of the tool call
toolName : string ; // The tool name (e.g., "navigate_to_page")
toolType : string ; // Tool type (e.g., "client", "server")
toolSubtype ?: string ; // Tool subtype for server events (e.g., "webhook", "knowledge")
arguments : Record < string , any >; // LLM-generated parameters
timestamp : string ; // ISO timestamp
timestampUserAction : string ; // Timestamp of the user action that triggered the tool call
userActionCorrelationId : string ; // Id of the user action that triggered the tool call
}
interface ToolCallCompletedPayload {
eventUid : string ; // Unique ID for this event
toolCallId : string ; // ID of the tool call
toolName : string ; // The tool name
toolType : string ; // Tool type
toolSubtype ?: string ; // Tool subtype
result : any ; // Result returned by the handler
executionTime : number ; // Execution time in milliseconds
timestamp : string ; // ISO timestamp
documentsAccessed ?: string []; // List of file names accessed during the tool call, if applicable (Knowledge tools only)
timestampUserAction : string ; // Timestamp of the user action that triggered the tool call
userActionCorrelationId : string ; // Id of the user action that triggered the tool call
}
interface ToolCallFailedPayload {
eventUid : string ; // Unique ID for this event
toolCallId : string ; // ID of the tool call
toolName : string ; // The tool name
toolType : string ; // Tool type
toolSubtype ?: string ; // Tool subtype
errorMessage : string ; // Error description
executionTime : number ; // Execution time in milliseconds
timestamp : string ; // ISO timestamp
timestampUserAction : string ; // Timestamp of the user action that triggered the tool call
userActionCorrelationId : string ; // Id of the user action that triggered the tool call
}
interface ToolCallHandler {
onStart ?: ( payload : ToolCallStartedPayload ) => Promise < string | void >;
onFail ?: ( payload : ToolCallFailedPayload ) => Promise < void >;
onComplete ?: ( payload : ToolCallCompletedPayload ) => Promise < void >;
}
ClientToolEvent is deprecated as of SDK v4.9.0. Use ToolCallStartedPayload with registerToolCallHandler or TOOL_CALL_STARTED events instead.
interface ClientToolEvent {
eventUid : string ; // Unique ID for this event
sessionId : string ; // Session ID
eventName : string ; // The tool name (e.g., "navigate_to_page")
eventData : Record < string , any >; // LLM-generated parameters
timestamp : string ; // ISO timestamp when event was created
timestampUserAction : string ; // ISO timestamp of user action that triggered this
userActionCorrelationId : string ; // Correlation ID for tracking
}
ConnectionClosedCode
enum ConnectionClosedCode {
NORMAL = 'CONNECTION_CLOSED_CODE_NORMAL' ,
MICROPHONE_PERMISSION_DENIED = 'CONNECTION_CLOSED_CODE_MICROPHONE_PERMISSION_DENIED' ,
SIGNALLING_CLIENT_CONNECTION_FAILURE = 'CONNECTION_CLOSED_CODE_SIGNALLING_CLIENT_CONNECTION_FAILURE' ,
WEBRTC_FAILURE = 'CONNECTION_CLOSED_CODE_WEBRTC_FAILURE' ,
SERVER_CLOSED_CONNECTION = 'CONNECTION_CLOSED_CODE_SERVER_CLOSED_CONNECTION' ,
}
ReasoningMessage
interface ReasoningMessage {
id : string ;
content : string ;
role : string ;
}
ReasoningStreamEvent
interface ReasoningStreamEvent {
id : string ;
content : string ;
endOfThought : boolean ;
role : string ;
}
Example Usage
Loading States
Use connection events to manage loading states:
anamClient . addListener ( AnamEvent . CONNECTION_ESTABLISHED , () => {
setIsConnecting ( false );
});
anamClient . addListener ( AnamEvent . SESSION_READY , ( sessionId : string ) => {
console . log ( "Session ready:" , sessionId );
setIsLoading ( false );
});
Connection Closed Handling
Handle connection closures with reason codes:
import { AnamEvent , ConnectionClosedCode } from "@anam-ai/js-sdk" ;
anamClient . addListener (
AnamEvent . CONNECTION_CLOSED ,
( reason : ConnectionClosedCode , details ?: string ) => {
switch ( reason ) {
case ConnectionClosedCode . NORMAL :
console . log ( "Connection closed normally" );
break ;
case ConnectionClosedCode . MICROPHONE_PERMISSION_DENIED :
showError ( "Microphone access is required" );
break ;
case ConnectionClosedCode . WEBRTC_FAILURE :
showError ( "Connection failed. Please check your network." );
break ;
default :
console . log ( "Connection closed:" , reason , details );
}
}
);
Microphone Permission Flow
Track microphone permission state:
anamClient . addListener ( AnamEvent . MIC_PERMISSION_PENDING , () => {
showPermissionPrompt ( "Please allow microphone access" );
});
anamClient . addListener ( AnamEvent . MIC_PERMISSION_GRANTED , () => {
hidePermissionPrompt ();
showMicrophoneIndicator ();
});
anamClient . addListener ( AnamEvent . MIC_PERMISSION_DENIED , ( error : string ) => {
showError ( `Microphone access denied: ${ error } ` );
});
Message History
Track conversation history:
import { Message } from "@anam-ai/js-sdk" ;
anamClient . addListener (
AnamEvent . MESSAGE_HISTORY_UPDATED ,
( messages : Message []) => {
setConversationHistory ( messages );
}
);
Real-time Transcription
Monitor speech in real-time:
import { MessageStreamEvent , MessageRole } from "@anam-ai/js-sdk" ;
anamClient . addListener (
AnamEvent . MESSAGE_STREAM_EVENT_RECEIVED ,
( event : MessageStreamEvent ) => {
if ( event . role === MessageRole . PERSONA ) {
updatePersonaSpeech ( event . content );
} else {
updateUserSpeech ( event . content );
}
if ( event . endOfSpeech ) {
finalizeSpeech ( event . id );
}
}
);
Use registerToolCallHandler to register handlers for specific tools. This automatically emits completed or failed events when the handler completes.
import { AnamClient } from "@anam-ai/js-sdk" ;
const cancelNavHandler = anamClient . registerToolCallHandler ( "navigate_to_page" , {
onStart : async ( payload ) => {
const { page , section } = payload . arguments ;
router . push ( `/ ${ page }${ section ? `# ${ section } ` : "" } ` );
},
onComplete : async ( payload ) => {
console . log ( `tool call completed ${ payload . toolName } ` );
},
onFail : async ( payload ) => {
console . log ( `tool call failed ${ payload . toolName } ` );
},
});
// you can also register partial handlers
const cancelModalHandler = anamClient . registerToolCallHandler ( "open_modal" , {
onStart : async ( payload ) => {
openModal ( payload . arguments . modalType , payload . arguments . data );
return `Opened ${ payload . arguments . modalType } modal` ;
},
});
// unsubscribe when no longer needed
cancelNavHandler ();
cancelModalHandler ();
registerToolCallHandler is the recommended approach for client tools. This will automatically emit completed or failed events when the handler completes.
Listen for tool call lifecycle events across all tool types — client, webhook, and knowledge tools all emit these events, so you can use them for logging, analytics, or monitoring:
import { AnamEvent , ToolCallStartedPayload , ToolCallCompletedPayload , ToolCallFailedPayload } from "@anam-ai/js-sdk" ;
anamClient . addListener (
AnamEvent . TOOL_CALL_STARTED ,
( event : ToolCallStartedPayload ) => {
console . log ( `Tool started: ${ event . toolName } ( ${ event . toolType } )` , event . arguments );
}
);
anamClient . addListener (
AnamEvent . TOOL_CALL_COMPLETED ,
( event : ToolCallCompletedPayload ) => {
console . log ( `Tool completed: ${ event . toolName } in ${ event . executionTime } ms` );
}
);
anamClient . addListener (
AnamEvent . TOOL_CALL_FAILED ,
( event : ToolCallFailedPayload ) => {
console . error ( `Tool failed: ${ event . toolName } - ${ event . errorMessage } ` );
}
);
Use toolType and toolSubtype to distinguish between tool types in your listeners:
anamClient . addListener ( AnamEvent . TOOL_CALL_COMPLETED , ( event ) => {
switch ( event . toolType ) {
case "client" :
console . log ( `Client action completed: ${ event . toolName } ` );
break ;
case "server" :
if ( event . toolSubtype === "webhook" ) {
console . log ( `Webhook responded: ${ event . toolName } in ${ event . executionTime } ms` );
} else if ( event . toolSubtype === "knowledge" ) {
console . log ( `Knowledge search completed: ${ event . toolName } ` );
}
break ;
}
});
Server Warnings
Handle server-side warnings:
anamClient . addListener ( AnamEvent . SERVER_WARNING , ( message : string ) => {
console . warn ( "Server warning:" , message );
showWarningToast ( message );
});
Reasoning Events (Extended Thinking)
Track AI reasoning when using models with extended thinking:
import { ReasoningMessage , ReasoningStreamEvent } from "@anam-ai/js-sdk" ;
// Get complete reasoning history
anamClient . addListener (
AnamEvent . REASONING_HISTORY_UPDATED ,
( messages : ReasoningMessage []) => {
setReasoningHistory ( messages );
}
);
// Stream reasoning in real-time
anamClient . addListener (
AnamEvent . REASONING_STREAM_EVENT_RECEIVED ,
( event : ReasoningStreamEvent ) => {
updateReasoningDisplay ( event . content );
if ( event . endOfThought ) {
finalizeThought ( event . id );
}
}
);
Removing Event Listeners
Remove listeners to prevent memory leaks, especially in single-page applications:
const handleMessages = ( messages : Message []) => {
setConversationHistory ( messages );
};
// Add listener
anamClient . addListener ( AnamEvent . MESSAGE_HISTORY_UPDATED , handleMessages );
// Remove listener when done
anamClient . removeListener ( AnamEvent . MESSAGE_HISTORY_UPDATED , handleMessages );
React Example
useEffect (() => {
const cancelNav = client . registerToolCallHandler ( "navigate_to_page" , {
onStart : async ( payload ) => {
router . push ( `/ ${ payload . arguments . page } ` );
},
});
const cancelModal = client . registerToolCallHandler ( "open_modal" , {
onStart : async ( payload ) => {
openModal ( payload . arguments . modalType );
return "Modal opened" ;
},
});
return () => {
cancelNav ();
cancelModal ();
};
}, [ client ]);
Learn More
Client Tools Guide Guide with examples for navigation, modals, UI updates, and more
Tools Overview Learn about all tool types: client, webhook, and knowledge tools