Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 179 additions & 90 deletions docs/content/en/4.ai/1.assistant.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,59 +27,25 @@ By default, the assistant connects to your documentation's built-in MCP server a

## Quick Start

### 1. Install dependencies

::code-group

```bash [npm]
npm install ai @ai-sdk/vue @ai-sdk/gateway @ai-sdk/mcp @comark/nuxt
```

```bash [pnpm]
pnpm add ai @ai-sdk/vue @ai-sdk/gateway @ai-sdk/mcp @comark/nuxt
```

```bash [yarn]
yarn add ai @ai-sdk/vue @ai-sdk/gateway @ai-sdk/mcp @comark/nuxt
```

::note{to="#custom-ai-provider"}
This quick start uses Vercel AI Gateway. To use another provider (Mistral, OpenAI, Cloudflare AI Gateway, or anything else supported by the AI SDK), see **Custom AI provider**.
::

### 2. Set up AI Gateway authentication
### 1. Set up AI Gateway authentication

Pick **one** of this method:
Pick **one** of these methods:

**API key** — Create a key in [Vercel AI Gateway](https://vercel.com/~/ai/api-keys) and add it to your environment:
**API key**: create a key in [Vercel AI Gateway](https://vercel.com/~/ai/api-keys) and add it to your environment:

```bash [.env]
AI_GATEWAY_API_KEY=your-api-key
```

**OIDC (only on Vercel)** — `VERCEL_OIDC_TOKEN` is injected automatically. Nothing to add in the production. For local dev, run `vercel env pull` on a [linked project](https://vercel.com/docs/cli/link).

### 3. Deploy

Deploy your site — the assistant is available as soon as authentication is configured.
**OIDC (only on Vercel)**: `VERCEL_OIDC_TOKEN` is injected automatically, so there is nothing to add in production. For local dev, run `vercel env pull` on a [linked project](https://vercel.com/docs/cli/link).

## Using the Assistant
### 2. Deploy

Users can interact with the assistant in multiple ways:

### Floating Input

On documentation pages, a floating input appears at the bottom of the screen. Users can type their questions directly and press Enter to get answers.

::tip
Use the keyboard shortcut :kbd{value="meta"} :kbd{value="I"} to focus the floating input.
::

### Explain with AI

Each documentation page includes an **Explain with AI** button in the table of contents sidebar. Clicking this button opens the assistant with the current page as context, asking it to explain the content.

### Slideover Chat

When a conversation starts, a slideover panel opens on the right side of the screen. This panel displays the conversation history and allows users to continue asking questions.
Deploy your site, the assistant is available as soon as authentication is configured.

## Configuration

Expand Down Expand Up @@ -111,7 +77,7 @@ export default defineAppConfig({
})
```

### FAQ Questions
### Questions

Display suggested questions when the chat is empty. This helps users discover what they can ask.

Expand Down Expand Up @@ -175,7 +141,7 @@ export default defineAppConfig({
})
```

## Keyboard Shortcuts
### Keyboard Shortcuts

Configure the keyboard shortcut for focusing the floating input:

Expand All @@ -196,7 +162,7 @@ The shortcut format uses underscores to separate keys. Common examples:
- `meta_k` - Cmd+K (Mac) / Ctrl+K (Windows)
- `ctrl_shift_p` - Ctrl+Shift+P

## Custom Icons
### Icons

Customize the icons used by the assistant:

Expand All @@ -216,20 +182,9 @@ export default defineAppConfig({

Icons use the [Iconify](https://iconify.design/) format (e.g., `i-lucide-sparkles`, `i-heroicons-sparkles`).

## Internationalization

All UI texts are automatically translated based on the user's locale. Docus includes built-in translations for English and French.
### Features

The following texts are translated:

- Slideover title and placeholder
- Tooltip texts
- Button labels ("Clear chat", "Close", "Explain with AI")
- Status messages ("Thinking...", "Chat is cleared on refresh")

## Disable Features

### Disable the Floating Input
#### Disable the Floating Input

Hide the floating input at the bottom of documentation pages:

Expand All @@ -241,7 +196,7 @@ export default defineAppConfig({
})
```

### Disable "Explain with AI"
#### Disable "Explain with AI"

Hide the "Explain with AI" button in the documentation sidebar:

Expand All @@ -253,32 +208,15 @@ export default defineAppConfig({
})
```

### Disable the Assistant Entirely

The assistant is disabled when no authentication is available. To explicitly disable it, remove `AI_GATEWAY_API_KEY` from your environment:

```bash [.env]
# AI_GATEWAY_API_KEY=your-api-key
```

On Vercel with OIDC, remove the auto-injected system environment variable from your project settings.

## Advanced Configuration
#### Disable the Assistant Entirely

Configure advanced options in `nuxt.config.ts` under `docus.assistant`.
Set `enabled` to `false` to disable the assistant, even when AI Gateway credentials are available:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
docus: {
assistant: {
// AI model (uses AI SDK Gateway format)
model: 'google/gemini-3-flash',

// MCP server (path or URL)
mcpServer: '/mcp',

// API endpoint path
apiPath: '/__docus__/assistant'
enabled: false
}
}
})
Expand Down Expand Up @@ -322,7 +260,7 @@ export default defineNuxtConfig({

This is useful when you want the assistant to answer questions from a different documentation source, or when connecting to a centralized knowledge base.

### Custom AI Model
### Model

The assistant uses `google/gemini-3-flash` by default. You can change this to any model supported by the AI SDK Gateway:

Expand All @@ -336,7 +274,7 @@ export default defineNuxtConfig({
})
```

### Site Name in Responses
### Site Name

The assistant automatically uses your site name in its responses. Configure the site name in `nuxt.config.ts`:

Expand All @@ -350,6 +288,157 @@ export default defineNuxtConfig({

This makes the assistant respond as "the My Documentation assistant" and speak with authority about your specific product.

## Custom provider

The `model` option above resolves models through Vercel AI Gateway, so it requires `AI_GATEWAY_API_KEY` or `VERCEL_OIDC_TOKEN`. To use another provider (Mistral, OpenAI, Cloudflare AI Gateway, or anything else supported by the [AI SDK](https://ai-sdk.dev/)), enable the assistant explicitly and provide your own endpoint.

::steps
### Enable the assistant and pick a path

Set `enabled: true` so the assistant no longer depends on AI Gateway credentials, and point `apiPath` at the route you're about to create:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
docus: {
assistant: {
enabled: true,
apiPath: '/api/assistant'
}
}
})
```

Your own server route always takes precedence: when you define a route at `apiPath`, Docus steps aside and doesn't register its built-in endpoint there.

### Install a provider

Install the AI SDK provider package you need, for example Mistral:

:::code-group
```bash [npm]
npm install @ai-sdk/mistral
```

```bash [pnpm]
pnpm add @ai-sdk/mistral
```

```bash [yarn]
yarn add @ai-sdk/mistral
```
:::

### Implement the endpoint

```ts [server/api/assistant.ts]
import { streamText, convertToModelMessages } from 'ai'
import { createMistral } from '@ai-sdk/mistral'

const mistral = createMistral()

export default defineEventHandler(async (event) => {
const { messages } = await readBody(event)

return createAssistantResponse(streamText({
...await getAssistantDefaultOptions(event),
model: mistral('mistral-large-latest'),
messages: await convertToModelMessages(messages)
}))
})
```

:::tip
Because you own the `streamText` call, provider specific constraints are solved where they belong.
:::

:::warning
Spread the defaults **first**. Options you set after the spread win (before are overwritten).
:::

| Util | Role |
| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`getAssistantDefaultOptions(event)`](#getassistantdefaultoptions) | Every `streamText` option the built-in endpoint uses: MCP tools, abort on disconnect, client cleanup, the documentation prompt, and the step and token limits. |
| [`getAssistantSystemPrompt(event)`](#getassistantsystemprompt) | The default documentation-tuned prompt on its own, for when you want to extend it. |
| [`createAssistantResponse(result)`](#createassistantresponse) | Wraps the result in the response format the assistant UI expects. |

#### `getAssistantDefaultOptions`

Returns real `streamText` options, so you can see and override every one of them:

| Option | Default |
| ------------------------ | ----------------------------------------------------------------------------------------- |
| `tools` | The MCP tools from `docus.assistant.mcpServer` |
| `abortSignal` | Aborts generation when the client disconnects |
| `onEnd` / `onAbort` | Closes the MCP client |
| `onError` | Logs the provider error server-side, then closes the MCP client |
| `instructions` | `getAssistantSystemPrompt(event)` |
| `maxOutputTokens` | `8000` |
| `maxRetries` | `2` |
| `stopWhen` | `isStepCount(10)` |
| `prepareStep` | Disables tools on the last step so the model answers instead of stopping mid tool-calling |
| `experimental_transform` | `smoothStream()` |

`model` and `messages` are not included, and neither are provider specific options like `providerOptions` or `temperature`, since they don't port across providers.

Override by setting the option after the spread:

```ts [server/api/assistant.ts]
return createAssistantResponse(streamText({
...await getAssistantDefaultOptions(event),
model: mistral('mistral-large-latest'),
// Wins over the default 8000
maxOutputTokens: 4000,
messages: await convertToModelMessages(messages)
}))
```

To add behaviour to a callback rather than replace it, keep a reference and call through to it, so MCP cleanup still runs:

```ts [server/api/assistant.ts]
const defaults = await getAssistantDefaultOptions(event)

return createAssistantResponse(streamText({
...defaults,
model: mistral('mistral-large-latest'),
messages: await convertToModelMessages(messages),
onError: (payload) => {
myErrorReporter(payload.error)
// Still closes the MCP client
defaults.onError(payload)
}
}))
```

:::warning
`onEnd`, `onAbort` and `onError` close the MCP client. Replacing one without calling through to the original leaks a connection per request.
:::

#### `getAssistantSystemPrompt`

`getAssistantDefaultOptions` already sets this prompt as `instructions`, so you only need this util to extend it. It returns a plain string, so concatenate:

```ts [server/api/assistant.ts]
const defaults = await getAssistantDefaultOptions(event)

return createAssistantResponse(streamText({
...defaults,
model: mistral('mistral-large-latest'),
messages: await convertToModelMessages(messages),
instructions: `${defaults.instructions}

**Extra instructions:**
- Always mention the minimum supported version
- Never speculate about the roadmap`
}))
```

Set `instructions` to your own string to replace the default entirely.

#### `createAssistantResponse`

Wraps a `streamText` result in the response format the assistant UI expects, so your route follows future stream format changes without being edited.
::

## Programmatic Access

Use the `useAssistant` composable to control the assistant programmatically:
Expand All @@ -371,13 +460,13 @@ function askQuestion() {
</template>
```

### Composable API
## Composable API

| Property | Type | Description |
| -------------------------------- | ---------------------- | --------------------------------------------------------------------------------------- |
| `isEnabled` | `ComputedRef<boolean>` | Whether the assistant is enabled (`AI_GATEWAY_API_KEY` or `VERCEL_OIDC_TOKEN` at build) |
| `isOpen` | `Ref<boolean>` | Whether the slideover is open |
| `open(message?, clearPrevious?)` | `Function` | Open the assistant, optionally with a message |
| `close()` | `Function` | Close the assistant slideover |
| `toggle()` | `Function` | Toggle the assistant open/closed |
| `clearMessages()` | `Function` | Clear the conversation history |
| Property | Type | Description |
| -------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `isEnabled` | `ComputedRef<boolean>` | Whether the assistant is enabled (`docus.assistant.enabled`, or `AI_GATEWAY_API_KEY` / `VERCEL_OIDC_TOKEN` at build) |
| `isOpen` | `Ref<boolean>` | Whether the slideover is open |
| `open(message?, clearPrevious?)` | `Function` | Open the assistant, optionally with a message |
| `close()` | `Function` | Close the assistant slideover |
| `toggle()` | `Function` | Toggle the assistant open/closed |
| `clearMessages()` | `Function` | Clear the conversation history |
Loading
Loading