> ## Documentation Index
> Fetch the complete documentation index at: /docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat API

> Send messages and receive AI responses

## Calling as a service

Most API calls represent one person chatting. If instead your **own backend** is calling BoostGPT on
behalf of many end users — a WhatsApp assistant, a helpdesk, a community bot — say so with
`purpose: 'service'`:

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  chat_id: 'community-42',
  message: 'What did we decide about the venue?',
  purpose: 'service',
  workspace_uuid: 'ws_abc123',
  chat_mode: 'edit'
});
```

This grants two things an ordinary call does not get:

* **A workspace of your choosing.** Pass `workspace_uuid` and the turn runs in that workspace, so
  your agent can keep durable notes and read them back on a later conversation.
* **A chat mode that sticks.** `'edit'` survives the request, so the agent can write files.

And deliberately withholds one: a service call is **not** a builder conversation. It never receives
the Site builder persona, and it never gets `read_conversations` — the tool that reads what *other*
people have asked. Workspace scope, never cross-conversation reach.

> [!NOTE]
>
> `purpose` is a request, not a credential. It is granted only when your API key belongs to someone who
> runs the project the bot is in; asking for it otherwise changes nothing and the call proceeds as
> normal. It is also opt-in — omit it and your existing integration behaves exactly as it does today.

### Workspaces and the tool round trip

A pinned workspace is remembered against the `chat_id`, so a turn that pauses for tool execution
resumes in the **same** workspace. You do not re-send `workspace_uuid` to `executeTool()`.

### Limits

Service workspaces are counted against their own plan allowance, separate from the workspaces you
create in the dashboard, and shown in your account usage. Neither allowance can be spent by the
other.

## Basic Chat

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Hello! How can you help me?'
});

if (result.err) {
  console.error('Error:', result.err);
} else {
  console.log('Bot response:', result.response);
}
```

### Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `bot_id` | string | Yes | Bot ID to chat with |
| `message` | string | Yes | User message |
| `model` | string | No | Override bot's model |
| `provider_key` | string | No | Use your own API key (BYOK) |
| `provider_host` | string | No | Required for Ollama (e.g., `http://localhost:11434`) |
| `instruction` | string | No | Override bot's instruction |
| `source_ids` | array | No | Narrow the knowledge search to these sources |
| `tags` | array | No | Narrow the knowledge search to these tags |
| `max_reply_tokens` | number | No | Override max tokens |
| `chat_id` | string | No | Chat ID to maintain conversation context |
| `stream` | boolean | No | Stream response (default: `false`) |
| `memory` | boolean | No | Search the agent's training data. Omit to use the agent's own setting |
| `reasoning_mode` | string | No | `auto`, `standard`, `agent` |
| `purpose` | string | No | `'service'` when this call is your own backend acting for many end users. See below |
| `workspace_uuid` | string | No | Pin the turn to a specific workspace. Requires `purpose: 'service'` |

### Response

```javascript theme={null}
{
  err: null,
  response: 'I can help you with customer support, product information, and answering your questions!'
}
```

## Chat with Conversation Context

Use `chat_id` to maintain conversation context:

```javascript theme={null}
const chatId = 'chat_user_123';

// First message
const msg1 = await client.chat({
  bot_id: 'bot_abc123',
  message: 'My name is John',
  chat_id: chatId
});

// Second message (bot remembers context)
const msg2 = await client.chat({
  bot_id: 'bot_abc123',
  message: 'What is my name?',
  chat_id: chatId
});

console.log(msg2.response); // "Your name is John"
```

## Override Model Per Request

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Complex question requiring deep thinking',
  model: 'gpt-5.4', // Use reasoning model for this request
  reasoning_mode: 'agent' // Autonomous multi-step with tools (up to 10x credit)
});
```

### Reasoning Modes

* **auto** - Automatically selects best approach
* **standard** - Quick answers (1x credit)
* **agent** - Autonomous multi-step reasoning with tool use (up to 10x)

## Use Local Ollama Models

For self-hosted models:

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Hello',
  model: 'llama3.1',
  provider_host: 'http://localhost:11434'
});
```

> [!NOTE]
>
> Use `provider_host` instead of `provider_key` for Ollama.

## Limit Response Length

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Give me a brief summary',
  max_reply_tokens: 200 // Short response
});
```

## Use Your Own API Key (BYOK)

Bring your own API key for any provider:

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Hello',
  model: 'gpt-6-luna',
  provider_key: 'sk-your-openai-key' // Use your OpenAI key
});
```

## Override Instructions

Override the bot's instruction per request:

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Tell me a joke',
  instruction: 'You are a comedian who tells funny jokes.'
});
```

## Use Specific Training Sources

Target specific training sources by ID:

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'What is our refund policy?',
  source_ids: ['source_123', 'source_456'], // Only search these sources
  tags: ['policies']                        // ...and only these tags
});
```

`source_ids` and `tags` narrow the search within the agent's own knowledge; they do not grant access
to another agent's. Both apply to an agent turn's `search_memory` tool as well as to a standard
reply — the agent chooses how many results to pull back, but it cannot widen the scope you set.

> [!NOTE]
>
> A tool continuation inherits the scope of the turn it resumes, so scoping a `chat()` call scopes
> every [`executeTool()`](/docs/sdk/core/api-reference#executetool) step that follows it — you do not need
> to re-send anything. Passing `source_ids` or `tags` to `executeTool()` overrides the turn's scope for
> that step; passing `[]` clears it.

## Disable Training Data

Skip the agent's training data for a specific request:

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Hello',
  memory: false // Don't search the agent's training data
});
```

Omitting `memory` uses the agent's own setting; sending `true` or `false` overrides it for that
request. On an agent turn the resolved value also decides whether the `search_memory` tool is offered
at all, so `memory: false` means the agent cannot reach back into its knowledge mid-turn either — and
it stays off for the tool continuations that follow, which inherit it.

## Stream Responses

Stream responses in real-time by setting `stream: true`:

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Write a long story',
  stream: true
});

if (result.err) {
  console.error('Error:', result.err);
} else {
  // Handle streaming response
  for await (const chunk of result.response) {
    process.stdout.write(chunk);
  }
}
```

## Edit Chat Mode

Edit mode routes your request through the agent reasoning pipeline, where the agent uses the built-in `edit` tool to make targeted code changes in your workspace files.

```javascript theme={null}
// Send an edit request — the agent finds and edits the relevant file
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Add email validation to the login form',
  chat_id: chatId,
  chat_mode: 'edit'
});

console.log(result.response); // Agent's summary of changes made
```

### Edit Mode Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `chat_mode` | string | No | `'ask'`, `'edit'`, or `'plan'` (default: `'ask'`) |

> [!NOTE]
>
> Edit mode forces agent reasoning — the AI analyzes your request, identifies the target file in the workspace, and applies precise string replacements using the built-in `edit` tool. The agent can chain multiple edits in a single turn. No `reference_message_id` is needed.

> [!WARNING]
>
> Edit mode requires the agent's **Workspace** setting to be enabled. If workspace is disabled, `edit` requests are treated as normal `ask` mode.

## Plan Chat Mode

Plan mode enables a conversational "plan-then-execute" workflow — the AI proposes a step-by-step plan before executing any tools, giving you the opportunity to review, modify, or approve.

```javascript theme={null}
// Step 1: Request a plan
const plan = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Find a professional studio background image and update the page',
  chat_id: chatId,
  chat_mode: 'plan'
});

console.log(plan.response); // AI proposes a step-by-step plan

// Step 2: Approve the plan to execute it
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Looks good, go ahead',
  chat_id: chatId,
  chat_mode: 'plan'
});

console.log(result.response); // Executed result

// Or modify the plan instead
const revised = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Actually, search for a darker background instead',
  chat_id: chatId,
  chat_mode: 'plan'
});

console.log(revised.response); // Revised plan
```

### Plan Mode Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `chat_mode` | string | No | `'ask'`, `'edit'`, or `'plan'` (default: `'ask'`) |

> [!NOTE]
>
> Plan mode classifies each message as one of three intents: **approve** (execute the proposed plan), **modify** (revise the plan), or **new** (generate a fresh plan). The AI is aware of all available tools (built-in and connected integrations) when generating plans. If no tools are needed, it bypasses planning and returns a direct answer. Plan generation costs 2 credits; execution costs are additional based on the tools used.

> [!WARNING]
>
> Plan mode requires the agent's **Workspace** setting to be enabled. If workspace is disabled, `plan` requests are treated as normal `ask` mode.

## Managing a Conversation

### Rename a chat

```javascript theme={null}
await client.renameChat({
  bot_id: 'bot_abc123',
  chat_id: 'chat-id',
  name: 'Onboarding questions'
});
```

### Set the stored chat mode

`chat()` takes `chat_mode` per message. `setChatMode` changes the conversation's stored default.

```javascript theme={null}
await client.setChatMode({ bot_id: 'bot_abc123', chat_id: 'chat-id', mode: 'plan' });
```

> [!WARNING]
>
> `edit` and `plan` are not available everywhere. They fall back to `ask` when the agent has no
> workspace, and a visitor conversation is always `ask` unless the caller is an owner, admin or
> moderator. `setChatMode` refuses outright with **403 "Only the builder conversation can use edit or
> plan mode."** for a non-staff caller on any conversation that is not the Site builder's. An API key
> inherits the role of the member who owns it, so a key owned by a plain member cannot set these.

### Cancel a reply in progress

```javascript theme={null}
await client.cancelChat({ bot_id: 'bot_abc123', chat_id: 'chat-id' });
```

### Stream state

```javascript theme={null}
// Is this conversation generating right now?
await client.fetchStreamStatus({ bot_id: 'bot_abc123', chat_id: 'chat-id' });

// Every conversation on this agent with a reply in flight
await client.fetchActiveStreams({ bot_id: 'bot_abc123' });
```

### Reconnect to a live reply

Both subscribe methods answer `text/event-stream`, so `response` is the raw stream rather than a
parsed object. This is how a client that dropped its connection mid-reply picks up the rest.

```javascript theme={null}
const { err, response } = await client.subscribeChat({
  bot_id: 'bot_abc123',
  chat_id: 'chat-id'
});

if (!err) {
  for await (const chunk of response) {
    process.stdout.write(chunk.toString());
  }
}

// Notifications for the whole agent; chat_id is optional
await client.subscribeNotifications({ bot_id: 'bot_abc123' });
```

### Schedules attached to this conversation

```javascript theme={null}
await client.fetchChatScheduledTasks({ bot_id: 'bot_abc123', chat_id: 'chat-id' });

// A toggle, not a setter: the endpoint flips the schedule's current state, so there is no
// target value to pass.
await client.toggleChatScheduledTask({
  bot_id: 'bot_abc123',
  chat_id: 'chat-id',
  task_id: 'task-id'
});
```

### The plan behind a conversation

```javascript theme={null}
const { response } = await client.fetchChatPlan({ bot_id: 'bot_abc123', chat_id: 'chat-id' });

// No accept method: a plan is accepted through the agent's own review question inside the
// conversation, never from outside it.
await client.cancelChatPlan({ bot_id: 'bot_abc123', chat_id: 'chat-id' });
```

### Agents delegated in a conversation

When an agent splits a task across subagents, each one is a record you can read, and the
conversation keeps them across turns — a later turn can resume one instead of starting over.

```javascript theme={null}
// This turn's agents…
const { response } = await client.fetchChatAgents({ bot_id: 'bot_abc123', chat_id: 'chat-id' });
for (const agent of response.agents) {
  console.log(agent.label, agent.status, `${agent.steps_used} steps`, `${agent.prompt_tokens} tokens`);
}

// …or every turn's, the way the dashboard's agent map shows them
const all = await client.fetchChatAgents({ bot_id: 'bot_abc123', chat_id: 'chat-id', scope: 'chat' });

// One agent in full: its brief, its report, and the tools it ran
const detail = await client.fetchChatAgent({ bot_id: 'bot_abc123', chat_id: 'chat-id', agent_id: response.agents[0].uuid });
console.log(detail.response.agent.transcript);

// Remove its record; a running agent is stopped first
await client.deleteChatAgent({ bot_id: 'bot_abc123', chat_id: 'chat-id', agent_id: response.agents[0].uuid });
```

## Error Handling

```javascript theme={null}
const result = await client.chat({
  bot_id: 'bot_abc123',
  message: 'Hello'
});

if (result.err) {
  if (result.err.includes('Rate limit')) {
    console.log('Rate limited, retry later');
  } else if (result.err.includes('Bot not found')) {
    console.log('Bot does not exist');
  } else {
    console.error('Unknown error:', result.err);
  }
} else {
  console.log('Success:', result.response);
}
```

## Complete Example

```javascript theme={null}
import { BoostGPT } from 'boostgpt';

const client = new BoostGPT({
  project_id: process.env.BOOSTGPT_PROJECT_ID,
  key: process.env.BOOSTGPT_API_KEY
});

async function chat() {
  const chatId = `chat_${Date.now()}`;

  // Start conversation
  const response1 = await client.chat({
    bot_id: 'bot_abc123',
    message: 'What services do you offer?',
    chat_id: chatId
  });

  if (response1.err) {
    console.error('Error:', response1.err);
    return;
  }

  console.log('Bot:', response1.response);

  // Follow-up question (remembers context)
  const response2 = await client.chat({
    bot_id: 'bot_abc123',
    message: 'How much does it cost?',
    chat_id: chatId
  });

  console.log('Bot:', response2.response);
}

chat();
```

## Next Steps

> [card] [Training Data](/docs/sdk/core/training-data.md)
>
> Add knowledge to improve responses

> [card] [API Reference](/docs/sdk/core/api-reference.md)
>
> Complete API documentation


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.