---
title: "Test Mode"
description: "Test your agent in the terminal without telephony, STT, or TTS."
icon: "flask"
---

# Test Mode

Test mode lets you interact with your agent in the terminal using pure text — no phone calls, no STT/TTS, no external services required. It simulates a phone conversation for rapid development.

## Quick Start

```typescript
import { Patter, Twilio, OpenAIRealtime } from "getpatter";

const phone = new Patter({ carrier: new Twilio(), phoneNumber: "+15550001234" });

const agent = phone.agent({
  engine: new OpenAIRealtime(),                         // OPENAI_API_KEY from env
  systemPrompt: "You are a helpful customer service agent for Acme Corp.",
  firstMessage: "Hello! Welcome to Acme Corp. How can I help you today?",
});

await phone.test({ agent });
```

This opens an interactive REPL:

```
============================================================
  PATTER TEST MODE
============================================================
  Agent: gpt-4o-mini-realtime-preview / alloy
  Provider: openai_realtime
  Call ID: test_a1b2c3d4e5f6
  Caller: +15550000001  →  Callee: +15550000002
------------------------------------------------------------
  Commands: /quit  /transfer <number>  /hangup  /history
============================================================

  Agent: Hello! Welcome to Acme Corp. How can I help you today?

  You: I need to return an item
  Agent: I'd be happy to help with your return...
```

## Commands

| Command | Description |
|---------|-------------|
| `/quit` | End the test session. |
| `/hangup` | Simulate hanging up the call. |
| `/transfer <number>` | Simulate a call transfer. |
| `/history` | Print the full conversation history. |

## Using with `onMessage`

Test mode works with custom message handlers, exactly as they would work in production:

```typescript
async function onMessage(data: Record<string, unknown>) {
  const userText = data.text as string;

  if (userText.toLowerCase().includes("cancel")) {
    return "Let me transfer you to our cancellation team.";
  }

  return `You said: ${userText}`;
}

await phone.test({ agent, onMessage });
```

The `onMessage` handler receives a single data object with `text`, `call_id`, `caller`, and `history` fields.

## Using with Built-in LLM Loop

When no `onMessage` handler is provided and `OPENAI_API_KEY` is available (either from `new OpenAIRealtime({ apiKey })` or the env var), test mode uses the built-in LLM loop with streaming responses:

```typescript
const agent = phone.agent({
  systemPrompt: "You are a restaurant booking assistant.",
  tools: [
    {
      name: "check_availability",
      description: "Check table availability",
      parameters: {
        type: "object",
        properties: {
          date: { type: "string" },
          partySize: { type: "number" },
        },
      },
      webhookUrl: "https://api.example.com/availability",
    },
  ],
});

await phone.test({ agent });
```

The LLM loop supports tool calling — tools are executed via their configured webhooks just like in production.

## Event Callbacks

Test mode fires the same lifecycle callbacks as `serve()`:

```typescript
await phone.test({
  agent,
  onCallStart: async (event) => {
    console.log(`Test call started: ${event.call_id}`);
  },
  onCallEnd: async (event) => {
    console.log(`Test call ended: ${event.call_id}`);
    const transcript = event.transcript as Array<unknown>;
    console.log(`Transcript: ${transcript.length} messages`);
  },
});
```

<Note>
  Test mode is designed for development only. It does not use any external APIs (except OpenAI for the LLM loop when no `onMessage` is provided).
</Note>
