Building a Custom Adapter

Step-by-step: implement the Adapter TypeScript interface, register the new adapter in the factory, write a test heartbeat, and deploy a custom Slack-bot agent as a working example.

Building a Custom Adapter

What you'll learn

Implement the three-method adapter interface to connect Paperclip to any AI service, including a worked example connecting to Groq's ultra-fast inference API.

The Three Files You Need

packages/server/src/lib/adapters/
├── groq.ts         ← your implementation
├── interface.ts    ← the contract you implement
└── factory.ts      ← register your adapter here

Step 1 — Implement the Interface

// packages/server/src/lib/adapters/groq.ts
import Groq from 'groq-sdk';
import type { Adapter, AdapterTask, AdapterInvokeResult, AdapterRunStatus } from './interface';

interface GroqConfig {
  model: string;
  api_key_env?: string;
  max_tokens?: number;
}

export class GroqAdapter implements Adapter {
  private client: Groq;
  private config: GroqConfig;

  constructor(config: GroqConfig) {
    this.config = config;
    const apiKey = config.api_key_env
      ? process.env[config.api_key_env]
      : process.env.GROQ_API_KEY;
    this.client = new Groq({ apiKey });
  }

  async invoke(task: AdapterTask): Promise<AdapterInvokeResult> {
    const response = await this.client.chat.completions.create({
      model: this.config.model ?? 'llama3-70b-8192',
      messages: [
        { role: 'system', content: task.systemPrompt },
        { role: 'user',   content: task.taskPrompt  },
      ],
      max_tokens: this.config.max_tokens ?? 2048,
    });

    const output = response.choices[0]?.message?.content ?? '';
    const usage  = response.usage;

    return {
      runId:  task.runId,
      status: 'completed',
      output,
      cost: {
        inputTokens:  usage?.prompt_tokens    ?? 0,
        outputTokens: usage?.completion_tokens ?? 0,
        costUsd:      ((usage?.prompt_tokens ?? 0) * 0.000_000_27)
                    + ((usage?.completion_tokens ?? 0) * 0.000_000_27),
        model: this.config.model,
      },
    };
  }

  // Groq is synchronous, so status/cancel are no-ops
  async status(_runId: string): Promise<AdapterRunStatus> {
    return { status: 'completed' };
  }

  async cancel(_runId: string): Promise<void> {}
}

Step 2 — Register in the Factory

// factory.ts — add one case:
case 'groq': return new GroqAdapter(agent.adapter_config as GroqConfig);

Step 3 — Add Pricing

// packages/server/src/lib/costs/pricing.ts
export const PRICING: Record<string, TokenPricing> = {
  // ... existing entries
  'llama3-70b-8192':  { input: 0.00027, output: 0.00027 },
  'llama3-8b-8192':   { input: 0.00005, output: 0.00008 },
};

Step 4 — Install the SDK

cd packages/server
pnpm add groq-sdk

Step 5 — Use the New Adapter

{
  "adapter_type": "groq",
  "adapter_config": {
    "model": "llama3-70b-8192",
    "api_key_env": "GROQ_API_KEY",
    "max_tokens": 2048
  }
}

Checkpoint ✓

Sign in for progress tracking & Q&A →