CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-hubot

A comprehensive chat bot framework modeled after GitHub's Campfire bot for building extensible chat bots across multiple platforms

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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;
}

docs

adapters-integration.md

brain-user-management.md

cli.md

core-bot-management.md

datastore.md

index.md

message-handling.md

scripts-middleware.md

tile.json