or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

adapters-integration.mdbrain-user-management.mdcli.mdcore-bot-management.mddatastore.mdindex.mdmessage-handling.mdscripts-middleware.md
tile.json

adapters-integration.mddocs/

Adapters and Integration

Adapter system for integrating with different chat platforms, including built-in Shell and Campfire adapters and extensibility patterns.

Capabilities

Adapter Base Class

The Adapter class provides the interface between hubot and chat services, handling message sending and receiving.

/**
 * Base adapter class for chat service integration
 * @param robot - Robot instance that owns this adapter
 */
class Adapter {
  constructor(robot: Robot);
  
  // Properties
  robot: Robot;
  
  // Abstract methods (must implement in subclasses)
  async send(envelope: Envelope, ...strings: string[]): Promise<void>;
  async reply(envelope: Envelope, ...strings: string[]): Promise<void>;
  async topic(envelope: Envelope, ...strings: string[]): Promise<void>;
  async play(envelope: Envelope, ...strings: string[]): Promise<void>;
  async run(): Promise<void>;
  close(): void;
  
  // Default implementations (can override in subclasses)
  async emote(envelope: Envelope, ...strings: string[]): Promise<void>;
  
  // Helper methods
  async receive(message: Message): Promise<void>;
}

Usage Example - Creating Custom Adapter:

import { Adapter, TextMessage } from "hubot";

class MyCustomAdapter extends Adapter {
  constructor(robot) {
    super(robot);
    this.client = null;
  }
  
  async run() {
    // Initialize connection to chat service
    this.client = new MyChatClient({
      token: process.env.CHAT_TOKEN,
      onMessage: (data) => this.handleMessage(data)
    });
    
    await this.client.connect();
    this.robot.logger.info("MyCustomAdapter connected");
  }
  
  async send(envelope, ...strings) {
    for (const string of strings) {
      await this.client.sendMessage(envelope.room, string);
    }
  }
  
  async reply(envelope, ...strings) {
    const user = envelope.user.name;
    for (const string of strings) {
      await this.client.sendMessage(envelope.room, `${user}: ${string}`);
    }
  }
  
  async emote(envelope, ...strings) {
    for (const string of strings) {
      await this.client.sendEmote(envelope.room, string);
    }
  }
  
  handleMessage(data) {
    const user = this.robot.brain.userForId(data.userId, {
      name: data.userName,
      room: data.room
    });
    
    const message = new TextMessage(user, data.text, data.id);
    this.receive(message);
  }
  
  close() {
    if (this.client) {
      this.client.disconnect();
    }
  }
}

// Use custom adapter
const robot = new Robot(new MyCustomAdapter(), true, "MyBot");

Built-in Shell Adapter

Interactive command-line adapter for local development and testing.

/**
 * Shell adapter for interactive command-line usage
 * Provides readline interface with command completion and history
 */
class Shell extends Adapter {
  constructor(robot: Robot);
  
  // Built-in commands
  // \q - quit
  // \? - help  
  // \c - clear screen
}

Environment Variables:

  • HUBOT_SHELL_HISTSIZE
    - Command history size (default: 1024)
  • HUBOT_SHELL_USER_ID
    - User ID for shell user (default: "1")
  • HUBOT_SHELL_USER_NAME
    - User name for shell user (default: "Shell")

Usage Example:

import { Robot } from "hubot";

// Create bot with Shell adapter
const robot = new Robot("Shell", true, "DevBot");

robot.hear(/hello/i, (res) => {
  res.send("Hello from the shell!");
});

await robot.run();
// Now you can interact via command line:
// > hello
// DevBot> Hello from the shell!

Built-in Campfire Adapter

Integration with 37signals Campfire chat service.

/**
 * Campfire adapter for 37signals Campfire chat
 * Supports real-time streaming, room management, and file uploads
 */
class Campfire extends Adapter {
  constructor(robot: Robot);
  
  // Additional Campfire-specific methods
  async lock(envelope: Envelope, ...strings: string[]): Promise<void>;
  async unlock(envelope: Envelope): Promise<void>;
}

Environment Variables:

  • HUBOT_CAMPFIRE_TOKEN
    - Campfire API authentication token
  • HUBOT_CAMPFIRE_ROOMS
    - Comma-separated list of room IDs to join
  • HUBOT_CAMPFIRE_ACCOUNT
    - Campfire account name

Usage Example:

// Set environment variables first
process.env.HUBOT_CAMPFIRE_TOKEN = "your-token";
process.env.HUBOT_CAMPFIRE_ROOMS = "12345,67890";
process.env.HUBOT_CAMPFIRE_ACCOUNT = "your-account";

const robot = new Robot("Campfire", true, "CampfireBot");

// Campfire-specific functionality
robot.hear(/lock room/i, (res) => {
  res.locked("Room is now locked!");
});

await robot.run();

Envelope Object

The envelope provides context for sending messages, containing room and user information.

/**
 * Message envelope containing delivery context
 */
interface Envelope {
  room: string;      // Room/channel identifier
  user: User;        // User who sent the original message
  message: Message;  // Original message that triggered response
}

Usage in Adapters:

// In adapter send method
async send(envelope, ...strings) {
  const room = envelope.room;
  const user = envelope.user;
  
  for (const string of strings) {
    await this.chatService.sendToRoom(room, string);
    this.robot.logger.info(`Sent to ${room}: ${string}`);
  }
}

Adapter Events

Adapters can emit events for monitoring and debugging.

// Adapter lifecycle events
adapter.emit('connected');
adapter.emit('disconnected');

// Message events
adapter.emit('send', envelope, string);
adapter.emit('reply', envelope, string);

// Error events
adapter.emit('error', error);

// Listen for adapter events
robot.adapter.on('connected', () => {
  robot.logger.info('Adapter connected successfully');
});

robot.adapter.on('error', (error) => {
  robot.logger.error('Adapter error:', error);
});

Message Processing Flow

Understanding how messages flow through the adapter system.

// 1. Chat service receives message
// 2. Adapter creates Message object
const message = new TextMessage(user, text, id);

// 3. Adapter calls receive() to send to robot
await this.receive(message);

// 4. Robot processes through middleware and listeners
// 5. Listener creates Response object
// 6. Response methods call back to adapter
await adapter.send(envelope, "Response text");

Adapter Configuration Patterns

Common patterns for configuring adapters with environment variables and options.

class MyAdapter extends Adapter {
  constructor(robot) {
    super(robot);
    
    // Required environment variables
    this.token = process.env.MY_ADAPTER_TOKEN;
    if (!this.token) {
      throw new Error("MY_ADAPTER_TOKEN environment variable required");
    }
    
    // Optional configuration with defaults
    this.timeout = parseInt(process.env.MY_ADAPTER_TIMEOUT) || 30000;
    this.retries = parseInt(process.env.MY_ADAPTER_RETRIES) || 3;
    
    // Configuration validation
    this.validateConfig();
  }
  
  validateConfig() {
    if (this.timeout < 1000) {
      throw new Error("Timeout must be at least 1000ms");
    }
  }
}

Third-party Adapter Integration

How to use external adapter packages from npm.

// Install external adapter
// npm install @hubot-friends/hubot-slack

// Use with adapter name
const robot = new Robot("@hubot-friends/hubot-slack", true, "SlackBot");

// Or with adapter path
const robot = new Robot("/path/to/my-adapter.js", true, "CustomBot");

// Set required environment variables
process.env.HUBOT_SLACK_TOKEN = "xoxb-your-token";
await robot.run();

Types

interface AdapterConstructor {
  new (robot: Robot): Adapter;
}

interface Envelope {
  room: string;
  user: User;
  message: Message;
}

interface AdapterOptions {
  timeout?: number;
  retries?: number;
  [key: string]: any;
}