Skip to content

Message Queue

The Message Queue feature provides automatic message buffering when the connection is unavailable. Messages are queued locally and automatically sent when the connection is restored.

Overview

When you call agent.send() while disconnected:

  1. The message is added to an internal queue
  2. The SDK continues without throwing an error
  3. When connection is restored, queued messages are sent automatically
  4. A queueFlushed event is emitted with the count of sent messages

This provides a seamless experience for users even with intermittent connectivity.

Quick Start

Message queuing works automatically:

typescript
import { AiAgent } from "@egain/ai-agent-sdk";

const agent = new AiAgent({
  id: "agent-id",
  endpoint: "https://your-endpoint.com"
});

await agent.initialize();

// This works even if disconnected!
await agent.send("Hello!");  // Queued if offline

// Check queue status
const queueSize = agent.getQueueSize();
console.log(`${queueSize} messages waiting`);

// Clear the queue if needed
agent.clearQueue();

Configuration

Configure queue behavior when creating the agent:

typescript
const agent = new AiAgent({
  id: "agent-id",
  endpoint: "https://your-endpoint.com",
  maxQueueSize: 1000  // Maximum messages to queue (default: 1000)
});

Configuration Options

OptionTypeDefaultDescription
maxQueueSizenumber1000Maximum number of messages to queue

Queue Events

Listen for queue-related events:

typescript
// When queued messages are sent after reconnection
agent.on("queueFlushed", (event) => {
  console.log(`Sent ${event.payload.count} queued messages`);
});

// When connection state changes
agent.on("stateChanged", (event) => {
  const { state, previousState } = event.payload;
  
  if (state === "RECONNECTING") {
    console.log("Reconnecting... messages will be queued");
  }
  
  if (state === "CONNECTED" && previousState === "RECONNECTING") {
    console.log("Reconnected! Queued messages will be sent");
  }
});

Queue Methods

Check Queue Size

typescript
const size = agent.getQueueSize();
console.log(`${size} messages in queue`);

Clear Queue

typescript
// Remove all queued messages
agent.clearQueue();

How It Works

Normal Flow (Connected)

User sends message → SDK sends immediately → Server receives

Offline Flow

User sends message → SDK queues locally → Connection restored → SDK sends queued messages

Automatic Flush

When the connection is established (or re-established), the SDK automatically:

  1. Checks for queued messages
  2. Sends them in order (FIFO)
  3. Emits queueFlushed event with count
typescript
agent.on("connected", () => {
  // Queue is automatically flushed after this
});

agent.on("queueFlushed", (event) => {
  console.log(`${event.payload.count} queued messages sent`);
});

Retry Behavior

The queue includes automatic retry logic:

BehaviorDescription
Max AttemptsEach message is retried up to 3 times
Failure HandlingFailed messages are removed after max attempts
Error EventsAn error event is emitted for failed messages
typescript
agent.on("error", (event) => {
  // Handle permanently failed messages
  console.error("Message failed:", event.payload.error);
});

UI Integration

Show Queue Status

typescript
function updateQueueIndicator() {
  const size = agent.getQueueSize();
  
  if (size > 0) {
    showBadge(`${size} pending`);
  } else {
    hideBadge();
  }
}

// Update on state changes
agent.on("stateChanged", updateQueueIndicator);
agent.on("queueFlushed", updateQueueIndicator);

React Example

tsx
function ConnectionStatus() {
  const [queueSize, setQueueSize] = useState(0);
  const [isConnected, setIsConnected] = useState(false);

  useEffect(() => {
    const updateStatus = () => {
      setQueueSize(agent.getQueueSize());
      setIsConnected(agent.isConnected());
    };

    agent.on("stateChanged", updateStatus);
    agent.on("queueFlushed", updateStatus);
    
    return () => {
      agent.off("stateChanged", updateStatus);
      agent.off("queueFlushed", updateStatus);
    };
  }, []);

  return (
    <div className="status">
      {isConnected ? (
        <span className="online">● Connected</span>
      ) : (
        <span className="offline">
          ○ Offline
          {queueSize > 0 && ` (${queueSize} pending)`}
        </span>
      )}
    </div>
  );
}

Vue Example

vue
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const queueSize = ref(0);
const isConnected = ref(false);

function updateStatus() {
  queueSize.value = agent.getQueueSize();
  isConnected.value = agent.isConnected();
}

onMounted(() => {
  agent.on('stateChanged', updateStatus);
  agent.on('queueFlushed', updateStatus);
  updateStatus();
});

onUnmounted(() => {
  agent.off('stateChanged', updateStatus);
  agent.off('queueFlushed', updateStatus);
});
</script>

<template>
  <div class="status">
    <span v-if="isConnected" class="online">● Connected</span>
    <span v-else class="offline">
      ○ Offline
      <template v-if="queueSize > 0">({{ queueSize }} pending)</template>
    </span>
  </div>
</template>

Handling Offline State

Optimistic UI Updates

Show messages immediately in the UI, even when queued:

typescript
async function sendMessage(text: string) {
  // Add to UI immediately (optimistic)
  addMessageToUI({
    text,
    status: agent.isConnected() ? "sent" : "pending"
  });

  // Send (queued if offline)
  const messageId = await agent.send(text);
  
  return messageId;
}

// Update status when flushed
agent.on("queueFlushed", () => {
  updatePendingMessagesStatus("sent");
});

Show Pending Indicator

typescript
function sendMessage(text: string) {
  const message = {
    id: Date.now().toString(),
    text,
    status: "sending"
  };
  
  addMessageToUI(message);
  
  agent.send(text).then(() => {
    if (agent.isConnected()) {
      updateMessageStatus(message.id, "sent");
    } else {
      updateMessageStatus(message.id, "queued");
    }
  });
}

Queue Limits

Max Queue Size

When the queue is full, send() will throw an error:

typescript
try {
  await agent.send("Message");
} catch (error) {
  if (error.message.includes("Queue is full")) {
    alert("Too many pending messages. Please wait for connection.");
  }
}

Handling Queue Full

typescript
async function safeSend(text: string) {
  const queueSize = agent.getQueueSize();
  const maxSize = 1000;  // Your configured max
  
  if (queueSize >= maxSize * 0.9) {
    showWarning("Message queue is almost full");
  }
  
  if (queueSize >= maxSize) {
    showError("Cannot send: too many pending messages");
    return null;
  }
  
  return await agent.send(text);
}

Best Practices

1. Show Queue Status to Users

typescript
agent.on("stateChanged", (event) => {
  if (event.payload.state === "RECONNECTING") {
    showToast("Reconnecting... messages will be sent when online");
  }
});

2. Handle Queue Full Gracefully

typescript
const MAX_QUEUE_WARNING = 900;

if (agent.getQueueSize() > MAX_QUEUE_WARNING) {
  disableSendButton();
  showWarning("Please wait for connection to restore");
}

3. Clear Queue on Logout

typescript
function logout() {
  agent.clearQueue();  // Don't send pending messages
  agent.disconnect();
}

4. Don't Clear Queue on Reconnect

The queue auto-flushes on reconnect. Don't clear it manually unless intentional:

typescript
// ❌ Don't do this
agent.on("connected", () => {
  agent.clearQueue();  // This loses messages!
});

// ✅ Let it auto-flush
agent.on("queueFlushed", (event) => {
  console.log(`Sent ${event.payload.count} pending messages`);
});

API Reference

Released under the MIT License.