Skip to content

Events ​

The SDK uses a type-safe event system for all communication. Events are the primary way to react to agent responses, connection state changes, and errors.

Event Structure ​

All events follow a consistent structure:

typescript
interface AgentEvent<T> {
  type: string;           // Event type identifier
  timestamp: number;      // Unix timestamp (ms)
  sessionId?: string;     // Current session ID
  agentId?: string;       // Agent ID
  payload: T;             // Event-specific data
}

Connection Events ​

connected ​

Emitted when WebSocket connection is established.

typescript
agent.on("connected", (event) => {
  console.log("Connected!", {
    sessionId: event.sessionId,
    agentId: event.agentId,
    timestamp: new Date(event.timestamp)
  });
});

closed ​

Emitted when connection is closed.

typescript
agent.on("closed", (event) => {
  const { code, reason } = event.payload;
  console.log(`Connection closed: ${code} - ${reason}`);
});

Payload:

PropertyTypeDescription
codenumber?WebSocket close code
reasonstring?Close reason

stateChanged ​

Emitted on any connection state transition.

typescript
agent.on("stateChanged", (event) => {
  const { state, previousState } = event.payload;
  console.log(`State: ${previousState} → ${state}`);
  
  switch (state) {
    case "CONNECTING":
      showConnectingIndicator();
      break;
    case "CONNECTED":
      hideConnectingIndicator();
      break;
    case "RECONNECTING":
      showReconnectingBanner();
      break;
    case "CLOSED":
      showDisconnectedMessage();
      break;
  }
});

Connection States:

StateDescription
IDLEInitial state, not connected
CONNECTINGEstablishing connection
CONNECTEDSuccessfully connected
RECONNECTINGAttempting reconnection
CLOSEDConnection closed

Message Events ​

message ​

Emitted for every incoming message (raw).

typescript
agent.on("message", (event) => {
  console.log("Raw message:", event.payload.data);
});

agentMessage ​

Emitted when an agent response is received (parsed and typed).

typescript
agent.on("agentMessage", (event) => {
  const { message, from, to, attachments } = event.payload;
  
  console.log("Agent says:", message?.content);
  console.log("From:", from?.name);
  
  if (attachments?.length) {
    console.log("Attachments:", attachments);
  }
});

Payload:

PropertyTypeDescription
messageMessageThe message object
typestringMessage type identifier
fromobject?Sender information
toobject?Recipient information
attachmentsarray?File attachments

errorMessage ​

Emitted when an error message is received from the agent.

typescript
agent.on("errorMessage", (event) => {
  const { message, error } = event.payload;
  
  console.error("Error from agent:", error.message);
  console.error("Original message:", message);
  
  // Optionally show user-friendly error
  showErrorToUser("Something went wrong. Please try again.");
});

heartbeat ​

Emitted when the agent is processing (typing indicator).

typescript
agent.on("heartbeat", (event) => {
  showTypingIndicator();
  
  // Auto-hide after timeout
  setTimeout(() => {
    hideTypingIndicator();
  }, 3000);
});

System Events ​

error ​

Emitted on SDK errors (connection, auth, message processing).

typescript
import { ConnectionError, AuthError, MessageError } from "@egain/ai-agent-sdk";

agent.on("error", (event) => {
  const error = event.payload.error;
  
  if (error instanceof ConnectionError) {
    console.error("Connection error:", error.message);
    // Maybe retry or show offline UI
  } else if (error instanceof AuthError) {
    console.error("Auth error:", error.message);
    // Redirect to login
  } else if (error instanceof MessageError) {
    console.error("Message error:", error.message);
    // Show message failed UI
  }
});

queueFlushed ​

Emitted when queued messages are sent after reconnection.

typescript
agent.on("queueFlushed", (event) => {
  console.log(`Sent ${event.payload.count} queued messages`);
  showNotification("Your messages have been sent!");
});

tokenExpiring ​

Emitted when authentication token is about to expire.

typescript
agent.on("tokenExpiring", async (event) => {
  const { reason, expiresAt } = event.payload;
  
  if (reason === "expiring") {
    console.log(`Token expires at: ${new Date(expiresAt!)}`);
  }
  
  // Refresh the token
  const newToken = await refreshToken();
  await agent.updateAccessToken(newToken);
});

Transcript Events ​

transcriptUpdate ​

Emitted whenever the transcript is updated (message sent or received). Use this to track all message activity in real-time.

typescript
agent.on("transcriptUpdate", (event) => {
  const { entry } = event.payload;
  
  console.log(`[${entry.direction.toUpperCase()}]`, entry.message.content);
  
  // Track sent vs received messages
  if (entry.direction === "sent") {
    console.log("User sent:", entry.message.content);
  } else {
    console.log("Agent replied:", entry.message.content);
  }
});

Payload:

PropertyTypeDescription
entryTranscriptEntryThe transcript entry that was added

TranscriptEntry:

PropertyTypeDescription
messageMessageThe message object
direction"sent" | "received"Message direction
timestampnumberWhen the entry was added
sessionIdstring | number?Session ID
agentIdstring | number?Agent ID

Use cases:

  • Building a custom chat UI that updates on every message
  • Logging all conversation activity
  • Analytics and message tracking
  • Syncing transcript with external systems

Portal and platform events ​

These events support the contact center portal initialization flow and platform connectors.

initialized ​

Emitted when the REST initialization pipeline finishes (portal / agent / profile resolution). Payload always includes enough identity for the agent; when the CC pipeline runs, it may also include portal details, selected profile, and available lists.

typescript
agent.on("initialized", async (event) => {
  const { portal, agent, profile, availablePortals, availableProfiles } = event.payload;
  await agent.connect();
});

Payload (subset):

PropertyTypeDescription
portalPortal?Selected portal
portalDetailsany?Raw portal details from API
agentAgentListItem | Record<string, unknown>?Resolved agent
profileUserProfile?Selected user profile
availableProfilesUserProfile[]?Profiles shown to the user
availablePortalsPortal[]?Portals shown to the user

portalsAvailable ​

User must pick a portal. Call agent.selectPortal(portal) with one of payload.portals.

typescript
agent.on("portalsAvailable", (e) => {
  agent.selectPortal(e.payload.portals[0]); // or show a picker
});

agentsAvailable ​

Flow B (initParams.isDefaultAgent === "true"): user must pick an agent. Call agent.selectAgent(agent).

profilesAvailable ​

User must pick a profile. Call agent.selectUserProfile(profile).

PropertyTypeDescription
profilesUserProfile[]Choices
selectedPortalPortalPortal context

callTranscriptUpdate ​

Telephony call transcript (platform connector), not the WebSocket chat transcript.

PropertyTypeDescription
entryCallTranscriptEntrysender, content, timestamp

callerInfoUpdate ​

PropertyTypeDescription
callerInfoCallerInfoCTI fields (name, phone, email, …)

conversationIdUpdate ​

PropertyTypeDescription
conversationIdstringPlatform interaction id

userContextUpdate ​

PropertyTypeDescription
userContextRecord<string, unknown>Merged context from connector

filterTagsUpdate ​

PropertyTypeDescription
filterTagsRecord<string, string[]>Tags from onPortalSelected / connector

contextValidation ​

Emitted when the platform rejects one or more context attributes without ending the session (non-terminal system message). Use this to surface validation errors in the UI without treating the message as a fatal errorMessage.

typescript
agent.on("contextValidation", (event) => {
  const { message, issues } = event.payload;
  for (const issue of issues) {
    console.warn("Context rejected:", issue.attribute, issue.reason);
  }
});
PropertyTypeDescription
messageMessageThe system message from the platform
issuesContextValidationIssue[]Rejected attributes and reasons

Event Handling Patterns ​

One-Time Listeners ​

typescript
// Handle only the first occurrence
agent.once("connected", () => {
  console.log("First connection established");
  initializeApp();
});

Removing Listeners ​

typescript
const handler = (event) => {
  console.log("Message:", event.payload);
};

// Add listener
agent.on("message", handler);

// Remove specific listener
agent.off("message", handler);

// Remove all listeners for event
agent.off("message");

Async Handlers ​

Event handlers can be async:

typescript
agent.on("agentMessage", async (event) => {
  const message = event.payload.message;
  
  // Async operations are supported
  await saveToDatabase(message);
  await updateUI(message);
});

Error Handling in Handlers ​

Errors in handlers are caught to prevent SDK crashes:

typescript
agent.on("message", (event) => {
  // This error won't crash the SDK
  throw new Error("Handler error");
});

// The SDK continues to work normally

TypeScript Support ​

All events are fully typed:

typescript
import type { AgentEvent, AgentEvents } from "@egain/ai-agent-sdk";

// Type-safe event handling
agent.on("agentMessage", (event: AgentEvent<"agentMessage">) => {
  // event.payload is fully typed
  const content = event.payload.message?.content;
});

// Custom typed handler
type MessageHandler = (event: AgentEvents["message"]) => void;

const handleMessage: MessageHandler = (event) => {
  console.log(event.payload.data);
};

Best Practices ​

1. Always Handle Errors ​

typescript
agent.on("error", (event) => {
  // Log for debugging
  console.error("SDK Error:", event.payload.error);
  
  // Report to error tracking
  errorTracker.capture(event.payload.error);
});

2. Show Connection State ​

typescript
agent.on("stateChanged", ({ payload }) => {
  updateConnectionIndicator(payload.state);
});

3. Use Heartbeat for UX ​

typescript
let typingTimeout: NodeJS.Timeout;

agent.on("heartbeat", () => {
  showTypingIndicator();
  
  clearTimeout(typingTimeout);
  typingTimeout = setTimeout(hideTypingIndicator, 2000);
});

agent.on("agentMessage", () => {
  clearTimeout(typingTimeout);
  hideTypingIndicator();
});

4. Clean Up on Unmount ​

typescript
// React example
useEffect(() => {
  const handleMessage = (event) => {
    setMessages(prev => [...prev, event.payload]);
  };
  
  agent.on("agentMessage", handleMessage);
  
  return () => {
    agent.off("agentMessage", handleMessage);
  };
}, []);

Released under the MIT License.