Skip to content

Using Request Interceptors with Embedded Chat

Overview

Request interceptors allow you to customize API requests made by the embedded JavaScript chat widget at runtime. This powerful feature enables you to inject dynamic body parameters based on your application's current state, user context, or tool configuration requirements.


When to Use Request Interceptors

Request interceptors are ideal for scenarios where you need to:

  • Tool Configuration: Provide tool-specific parameters like company IDs or data filters
  • Contextual Data: Include user preferences, application state, or environmental information
  • Dynamic Content: Add context files or modify memory settings based on user permissions

Basic Implementation

To use request interceptors, add the requestInterceptor function to your widget initialization:

window.WabeeChat.init({
  target: '#chat-container',
  apiKey: 'YOUR_API_KEY',
  agentId: 'YOUR_AGENT_ID',
  agentUrl: 'https://your-agent-url.com',
  sseUrl: 'https://your-sse-url.com',
  fileServiceUrl: 'https://your-file-service-url.com',

  // Request interceptor function
  requestInterceptor: (config) => {
    // Modify config.body as needed
    return config;
  }
});

Configuration Object

The interceptor function receives a configuration object with:

Property Type Description
body Record<string, unknown> Request body data (optional)
message string User's message

Using Data Filter Hints

One of the most powerful uses of request interceptors is to dynamically apply data filter hints that control how your agent's tools access and filter data:

requestInterceptor: (config) => {
  const user = getCurrentUser();
  const company = getCompany();

  // Configure tools with dynamic filters for data access control
  config.body.data_filter_hints = [
    {
      tool_name: "CustomerDataTool",
      filter_type: "equals",
      filter_key: "company_id",
      filter_value: company.id
    },
    {
      tool_name: "CustomerDataTool",
      filter_type: "equals",
      filter_key: "user_department",
      filter_value: user.department
    }
  ];

  return config;
}

Available Filter Types

Filter Type Description Example Use Case
equals Exact match company_id = "123"
gt Greater than date > "2024-01-01"
lt Less than price < 100
gte Greater than or equal score >= 85
lte Less than or equal age <= 65
like Pattern matching name LIKE "%smith%"

Role-Based Data Access

Implement different data access levels based on user permissions:

requestInterceptor: (config) => {
  const user = getCurrentUser();
  const company = getCompany();

  // Base filter for company isolation
  const baseFilters = [
    {
      tool_name: "CustomerDataTool",
      filter_type: "equals",
      filter_key: "company_id",
      filter_value: company.id
    }
  ];

  // Add role-specific filters
  if (user.role === 'admin') {
    // Admins see all company data
    config.body.data_filter_hints = baseFilters;
  } else if (user.role === 'manager') {
    // Managers see their department's data
    config.body.data_filter_hints = [
      ...baseFilters,
      {
        tool_name: "CustomerDataTool",
        filter_type: "equals",
        filter_key: "department",
        filter_value: user.department
      }
    ];
  } else {
    // Regular users see only their assigned data
    config.body.data_filter_hints = [
      ...baseFilters,
      {
        tool_name: "CustomerDataTool",
        filter_type: "equals",
        filter_key: "assigned_user_id",
        filter_value: user.id
      }
    ];
  }

  return config;
}

Additional Configuration Options

Context Files and Memory

requestInterceptor: (config) => {
  // Include relevant context files
  config.body.context_files = [
    "inputs/chat-files/user123/project-requirements.pdf",
    "inputs/chat-files/user123/meeting-notes.txt"
  ];

  // Enable memory retention for premium users
  const user = getCurrentUser();
  config.body.auto_memory_retain = user.plan === 'premium';

  return config;
}

Message-Based Logic

Customize behavior based on the user's message content:

requestInterceptor: (config) => {
  const message = config.message.toLowerCase();

  if (message.includes('customer') || message.includes('client')) {
    config.body.context_files = [
      "inputs/customer-data/current-customers.csv"
    ];

    config.body.data_filter_hints = [
      {
        tool_name: "CustomerDatabase",
        filter_type: "equals",
        filter_key: "status",
        filter_value: "active"
      }
    ];
  }

  return config;
}

Async Operations

Request interceptors support asynchronous operations:

requestInterceptor: async (config) => {
  try {
    // Fetch dynamic data
    const userProfile = await fetchUserProfile();
    const permissions = await fetchUserPermissions();

    config.body.data_filter_hints = [
      {
        tool_name: "UserDataTool",
        filter_type: "equals",
        filter_key: "user_id",
        filter_value: userProfile.id
      }
    ];

    return config;
  } catch (error) {
    console.warn('Failed to fetch user data for request interceptor:', error);
    return config; // Return original config if async operations fail
  }
}

Complete Example

window.WabeeChat.init({
  target: '#chat-container',
  apiKey: 'wabee_api_key_example_123',
  agentId: 'agent-uuid-here',
  agentUrl: 'https://api.wabee.ai',
  sseUrl: 'https://sse.wabee.ai',
  fileServiceUrl: 'https://files.wabee.ai',

  requestInterceptor: (config) => {
    const user = getCurrentUser();
    const company = getCompany();

    // Configure data filter hints for multi-tenant data access
    config.body.data_filter_hints = [
      {
        tool_name: "BubbleDataTool",
        filter_type: "equals",
        filter_key: "company_id",
        filter_value: company.id
      },
      {
        tool_name: "BubbleDataTool", 
        filter_type: "equals",
        filter_key: "access_level",
        filter_value: user.accessLevel
      }
    ];

    // Enable memory retention for premium users
    config.body.auto_memory_retain = user.plan === 'premium';

    return config;
  }
});

Error Handling and Security

Built-in Error Handling

The widget includes automatic error handling: - If the interceptor throws an error, the original request configuration is used - Errors are logged to the console with warning messages - Chat functionality continues working normally

Security Best Practices

  1. Sensitive Data: Avoid logging sensitive information in the interceptor
  2. Input Validation: Validate user input before including it in requests
  3. Token Management: Ensure tokens and API keys are securely stored and regularly refreshed
  4. Access Control: Implement proper access control checks before setting filter values
requestInterceptor: (config) => {
  try {
    // Your custom logic here
    config.body.data_filter_hints = processDataFilters();
    return config;
  } catch (error) {
    console.warn('Custom interceptor logic failed:', error);
    return config; // Return config as-is if errors occur
  }
}

Troubleshooting

Common Issues

  • Interceptor Not Called: Ensure the function is properly defined in the init options
  • Filter Hints Ignored: Check that tool names match exactly and filter types are valid
  • Body Parameters Ignored: Ensure body parameter names match the expected API schema

Debugging

Enable browser developer tools to monitor: - Network requests to see applied body data - Console warnings for interceptor errors - Request/response timing and status codes

requestInterceptor: (config) => {
  console.log('Original config:', config);

  // Your modifications
  config.body.data_filter_hints = [
    {
      tool_name: "DebugTool",
      filter_type: "equals", 
      filter_key: "debug_mode",
      filter_value: "enabled"
    }
  ];

  console.log('Modified config:', config);
  return config;
}

Next Steps