Skip to content
+

Chat - Echo adapter

Echo user messages back through the chat runtime to prototype UI without a backend.

Echoing user messages

The adapter below echoes whatever you type after the default 400 ms simulated network delay. The reply arrives as a single text chunk once the delay elapses — the Echo adapter doesn't simulate token-by-token streaming. For real streamed output, swap in createAiSdkAdapter.

Echo

Assistant

Type anything — I echo it back with a small delay.

'use client';
import { ChatBox } from '@mui/x-chat';
import { createEchoAdapter } from '@mui/x-chat/headless';

const CONVERSATION_ID = 'echo-demo';

const initialConversations = [{ id: CONVERSATION_ID, title: 'Echo' }];

const initialMessages = [
  {
    id: 'welcome',
    conversationId: CONVERSATION_ID,
    role: 'assistant' as const,
    status: 'sent' as const,
    parts: [
      {
        type: 'text' as const,
        text: 'Type anything — I echo it back with a small delay.',
      },
    ],
  },
];

const adapter = createEchoAdapter({
  respond: (text) => `You typed: "${text || 'nothing'}".`,
});

export default function EchoAdapterDemo() {
  return (
    <ChatBox
      adapter={adapter}
      initialActiveConversationId={CONVERSATION_ID}
      initialConversations={initialConversations}
      initialMessages={initialMessages}
      sx={{
        height: 500,
        border: '1px solid',
        borderColor: 'divider',
        borderRadius: 1,
      }}
    />
  );
}

Usage

Use respond to set the reply text and delayMs to control the response delay:

import { createEchoAdapter } from '@mui/x-chat/headless';

const adapter = createEchoAdapter({
  respond: (text) => `Mock reply for: ${text}`,
  delayMs: 200,
});

Canned replies

Return different replies based on the input to script deterministic flows for demos and tests:

Canned replies

Assistant

Try asking about "pricing" or "support".

'use client';
import { ChatBox } from '@mui/x-chat';
import { createEchoAdapter } from '@mui/x-chat/headless';

const CONVERSATION_ID = 'canned-demo';

const initialConversations = [{ id: CONVERSATION_ID, title: 'Canned replies' }];

const initialMessages = [
  {
    id: 'welcome',
    conversationId: CONVERSATION_ID,
    role: 'assistant' as const,
    status: 'sent' as const,
    parts: [
      {
        type: 'text' as const,
        text: 'Try asking about "pricing" or "support".',
      },
    ],
  },
];

const adapter = createEchoAdapter({
  respond: (text) => {
    const input = text.toLowerCase();
    if (input.includes('pricing')) {
      return 'Plans start at $0 — the echo tier is free forever.';
    }
    if (input.includes('support')) {
      return 'Support is instant: I only ever talk to you.';
    }
    return `I only know about "pricing" and "support", but you said: "${text}".`;
  },
});

export default function EchoAdapterCannedReplies() {
  return (
    <ChatBox
      adapter={adapter}
      initialActiveConversationId={CONVERSATION_ID}
      initialConversations={initialConversations}
      initialMessages={initialMessages}
      sx={{
        height: 500,
        border: '1px solid',
        borderColor: 'divider',
        borderRadius: 1,
      }}
    />
  );
}

Options

createEchoAdapter() returns a complete ChatAdapter, so it plugs into the same adapter prop as any production adapter.

Option Type Default Description
respond (text: string) => string text => 'You said: "…". Replace this demo adapter with your own API call.' Builds the assistant reply from the user's text.
delayMs number 400 Milliseconds to wait before emitting the reply. Simulates network/model latency so the UI doesn't feel jarringly instant.

Cancellation: the adapter honors the abort signal passed to sendMessage(). Calling stopStreaming() from the useChat hook — or switching conversations — while the simulated delay is pending closes the stream without emitting a reply. See Streaming for the cancellation lifecycle.

When to use it

  • Prototyping: get a chat surface running before any backend exists, so you can iterate on layout, theming, and message rendering.
  • Smoke tests: drive <ChatBox> through full send/receive cycles in your test suite without a real LLM.
  • Demos and Storybook: ship examples that run anywhere — no API keys, no network, identical output every run.

Swap to a real adapter (for example createAiSdkAdapter) when you're ready to wire a backend.

See also