Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
155 changes: 131 additions & 24 deletions docs/content/en/4.ai/1.assistant.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +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).
**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).

### 3. Deploy
### 2. Deploy

Deploy your site the assistant is available as soon as authentication is configured.
Deploy your site, the assistant is available as soon as authentication is configured.

## Using the Assistant

Expand Down Expand Up @@ -255,7 +241,19 @@ 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:
Set `enabled` to `false` to disable the assistant, even when AI Gateway credentials are available:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
docus: {
assistant: {
enabled: false
}
}
})
```

The assistant is also disabled when no authentication is available, so removing `AI_GATEWAY_API_KEY` from your environment has the same effect:

```bash [.env]
# AI_GATEWAY_API_KEY=your-api-key
Expand All @@ -271,6 +269,9 @@ Configure advanced options in `nuxt.config.ts` under `docus.assistant`.
export default defineNuxtConfig({
docus: {
assistant: {
// Force enable or disable the assistant
enabled: true,

// AI model (uses AI SDK Gateway format)
model: 'google/gemini-3-flash',

Expand Down Expand Up @@ -336,6 +337,112 @@ export default defineNuxtConfig({
})
```

### Custom AI 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.

#### 1. 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.

#### 2. Implement the endpoint

The endpoint is a regular Nitro route, so you have two options:

| Approach | Use it when |
| -------- | ----------- |
| [Reuse the built-in handler](#reuse-the-built-in-handler) | You only need to swap the model, the system prompt, or the provider options. MCP tool wiring, streaming, and abort handling stay in place. |
| [Write your own handler](#write-your-own-handler) | You need full control over tools, message handling, or the streaming pipeline. |

#### Reuse the built-in handler

`assistantSearchHandler` is an auto-imported server util that contains the default endpoint logic: MCP tool wiring, streaming, and abort handling. Pass a `model` to change the provider.

Install the 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
```

::

Then build the route:

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

const mistral = createMistral()

export default defineEventHandler(event => assistantSearchHandler(event, {
model: mistral('mistral-large-latest')
}))
```

That's the whole integration: everything else, including the documentation-tuned system prompt, keeps working as before.

`assistantSearchHandler` accepts an optional config object as its second argument:

| Property | Type | Description |
| ----------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `model` | `LanguageModel` | Any AI SDK model. Defaults to `docus.assistant.model` resolved through Vercel AI Gateway. |
| `systemPrompt` | `string \| (event, { siteName }) => string` | Replaces the built-in prompt. Use `getAssistantSystemPrompt(siteName)` to extend the default instead of replacing it. |
| `providerOptions` | `ProviderOptions` | Provider specific options passed to `streamText`. Defaults to Vercel AI Gateway caching, and is omitted when you pass a custom `model`. |

#### Write your own handler

Skip `assistantSearchHandler` entirely and implement the route yourself. The assistant UI talks to it through the AI SDK's `DefaultChatTransport`, so the handler only has to respect two things:

- It receives a `POST` with a `{ messages }` body, where `messages` is an array of AI SDK `UIMessage`.
- It returns a UI message stream response, built with `createUIMessageStreamResponse`.

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

const mistral = createMistral()

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

const result = streamText({
model: mistral('mistral-large-latest'),
instructions: getAssistantSystemPrompt('My Documentation'),
messages: await convertToModelMessages(messages)
})

return createUIMessageStreamResponse({
stream: toUIMessageStream({ stream: result.stream })
})
})
```

::warning
A handler written from scratch loses everything the built-in one provides: MCP tool wiring, step limits, abort handling on client disconnect, and stream smoothing. Wire in your own `tools` if you want the assistant to keep searching your documentation.
::

### Site Name in Responses

The assistant automatically uses your site name in its responses. Configure the site name in `nuxt.config.ts`:
Expand Down Expand Up @@ -375,7 +482,7 @@ function askQuestion() {

| Property | Type | Description |
| -------------------------------- | ---------------------- | --------------------------------------------------------------------------------------- |
| `isEnabled` | `ComputedRef<boolean>` | Whether the assistant is enabled (`AI_GATEWAY_API_KEY` or `VERCEL_OIDC_TOKEN` at build) |
| `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 |
Expand Down
Loading
Loading