> Fetch clean Markdown by appending `.md` to any page URL under https://signalwire.com/docs or requesting it with the HTTP header `Accept: text/markdown`. The root index at https://signalwire.com/docs/llms.txt lists the available documentation indexes.

# chat

> Send a message to an AI agent and return its reply.

[ref-aichatclient]: /docs/server-sdks/reference/typescript/agents/ai-chat-client

[createconversation]: /docs/server-sdks/reference/typescript/agents/ai-chat-client/create-conversation

[swml-user-event]: /docs/server-sdks/reference/typescript/agents/function-result/swml-user-event

Send a message and return the agent's reply. One call is one full turn,
including any tool calls the agent makes along the way, so expect seconds
rather than milliseconds.

## **Parameters**

**`conversationId`** `string` — required

The conversation to send on.

---

**`message`** `string` — required

The message to send.

---

**`options`** `ChatOptions`

Turn options.

---

**`options.role`** `string` — default: user

`user` or `system`. A `system` message steers the agent without appearing as
something the user said.

---

**`options.configUrl`** `string`

Creates the conversation if it does not exist yet. Saves a call, at the cost
of never receiving `initialMessage`, so the agent does not speak first.

---

**`options.userMetadata`** `Record<string, unknown>`

Arbitrary data about the user, echoed back on this conversation's webhooks.
Sent as `user_meta_data`.

---

**`options.timeout`** `number`

Applies only when this call creates the conversation.

---

**`options.reinit`** `boolean` — default: false

Applies only when this call creates the conversation.

---

## **Returns**

`Promise<ChatResponse>` -- carries `text`, `conversationId`, and `userEvent`.

`userEvent` is `null` unless the turn produced one. Its contents are whatever
your tool passed to [`swmlUserEvent()`][swml-user-event], so the shape is yours.

## **Throws**

`ChatInProgressError` when a turn is already running on this conversation. That
is the contract rather than a transient failure, so wait for the first turn to
return instead of retrying.

## **Example**

```typescript {8-11}
import { AIChatClient, ChatInProgressError } from '@signalwire/sdk';

const CONFIG_URL = 'https://bayview-taxi.example.com/swml';
const client = new AIChatClient({ space: 'your-space' });
await client.createConversation('chat-8f21', { configUrl: CONFIG_URL });

try {
  const reply = await client.chat(
    'chat-8f21',
    'How much is a van from 123 Gough Street to the airport?',
  );
  console.log('Ada:', reply.text);
  if (reply.userEvent) handle(reply.userEvent);
} catch (e) {
  if (e instanceof ChatInProgressError) {
    // a turn is already running; wait rather than retry
  } else {
    throw e;
  }
}
```