Built-in AI chat assistant

View source
Movk Nuxt Docs includes a built-in AI Chat module that integrates deeply with your docs through MCP tools, supporting streaming responses, code highlighting, multi-model switching, and a floating input. Learn how to configure models, customize providers, write a system prompt, and use useAIChat to control the chat state.

Overview

A Nuxt module that provides an AI chat interface powered by MCP (Model Context Protocol) tools.

AiChat

Quick start

Movk Nuxt Docs already includes the AI Chat module. To enable it, apply the following configuration:

Add the module configuration in nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@movk/nuxt-docs'],
  aiChat: {
    model: 'zai/glm-4.7',
    models: [
      'zai/glm-4.7',
      'anthropic/claude-sonnet-4.6',
      'google/gemini-2.5-flash'
    ],
  }
})

Module configuration options:

OptionTypeDefaultDescription
apiPathstring/api/ai-chatThe chat API endpoint path
mcpPathstring/mcpThe MCP server connection path
modelstring-The model identifier
modelsstring[][]The list of available models (in "provider/model" or "model" format)

Configure the AI Chat features in app/app.config.ts:

app/app.config.ts
export default defineAppConfig({
  aiChat: {
    floatingInput: true,
    explainWithAi: true,
    faqQuestions: [
      {
        category: 'Quick start',
        items: ['How do I install it?', 'How do I configure it?'],
      },
      {
        category: 'Advanced usage',
        items: ['How do I customize it?'],
      },
    ],
    shortcuts: {
      focusInput: 'meta_i'
    },
    texts: {
      title: 'AI Assistant',
      placeholder: 'Type your question...',
      // ... more text configuration
    }
  }
})
See the full AI Chat configuration options
When multiple languages are enabled, faqQuestions can be an object grouped by locale (e.g. { 'zh-CN': [...], 'en': [...] }), and the panel switches with the current locale.

Set your API key as an environment variable:

.env
# AI Gateway: a single key proxying multiple providers (recommended)
AI_GATEWAY_API_KEY=your-gateway-key

# Or connect directly to a built-in provider: configure as needed; the matching prefix bypasses the Gateway and uses the official SDK directly
DEEPSEEK_API_KEY=your-deepseek-key
ALIBABA_API_KEY=your-alibaba-key
ZHIPU_API_KEY=your-zhipu-key
AI Chat is enabled as long as AI_GATEWAY_API_KEY or any built-in provider key (see the table below) is present; if all are missing, the module is disabled and logs a message to the console.

Automatic integration

The AI Chat feature is built into Movk Nuxt Docs, with no need to add components manually.

By default, the following features are enabled automatically:

  • AI Chat trigger button: shown on the right side of the page; clicking it opens the AI assistant panel
  • Floating input: shown at the bottom of documentation pages (controlled via appConfig.aiChat.floatingInput)
  • AI explain button: shown in the documentation sidebar (controlled via appConfig.aiChat.explainWithAi)

Manual integration (optional)

If you need to use the AI Chat components on a custom page:

<template>
  <div>
    <AiChat />
    <AiChatPanel />
  </div>
</template>
FAQ questions are now configured in app/app.config.ts, with no need to pass props in the component.

Floating input

The floating input is integrated at the bottom of documentation pages by default. To use it on a custom page:

<template>
  <div>
    <Teleport to="body">
      <ClientOnly>
        <AiChatPanel />
        <AiChatFloatingInput />
      </ClientOnly>
    </Teleport>
  </div>
</template>
Use Teleport to render the floating input at the body level, ensuring it stays pinned to the bottom regardless of where it sits in the component hierarchy

Programmatic control

Use the useAIChat composable to control the chat:

<script setup>
const {
  isEnabled,
  isOpen,
  messages,
  toggleChat,
  open
} = useAIChat()

// Open the chat and send an initial message
open('How do I install this module?')

// Toggle chat visibility
toggle()
</script>

Customization

Custom model providers

See the list of providers supported by the AI SDK
server/plugins/modelProviders.ts
import { modelProviderRegistry } from '#ai-chat/server/utils/modelProviders'
import { createAnthropic } from '@ai-sdk/anthropic'

export default defineNitroPlugin(() => {
  // Override the default provider configuration
  modelProviderRegistry.register('anthropic', ({ config, modelId }) => {
    const anthropic = createAnthropic({
      apiKey: config.anthropicApiKey,
      // Custom configuration...
    })
    return anthropic(modelId)
  })
})

Configure the environment variable:

.env
ANTHROPIC_API_KEY=your_api_key

Built-in providers

After configuring the corresponding environment variable, models matching a prefix connect directly to the official SDK; models that do not match any prefix fall back to the AI Gateway. An optional <PROVIDER>_BASE_URL (e.g. ALIBABA_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 to switch to Alibaba Cloud's China endpoint) overrides the endpoint/region. Registering the same prefix with modelProviderRegistry.register(prefix, ...) in server/plugins/ overrides the built-in implementation.

ProviderPrefixEnvironment variable
OpenAIopenaiOPENAI_API_KEY
AnthropicanthropicANTHROPIC_API_KEY
DeepSeekdeepseekDEEPSEEK_API_KEY
Alibaba Cloud QwenalibabaALIBABA_API_KEY
Zhipu GLMzaiZHIPU_API_KEY
AI Gatewaynone (fallback)AI_GATEWAY_API_KEY

System prompt

To customize the AI's behavior, create or edit the system prompt in the following file: server/api/ai-chat.ts

Default system prompt

Styling

The components use Nuxt UI and Tailwind CSS design tokens. You can customize the appearance by modifying the component files or overriding UI properties.

API

AiChat

The simplest way to integrate, showing the assistant button.

View source code

AiChatFloatingInput

A floating input at the bottom of the viewport. Requires no props.

Keyboard shortcuts:

  • ⌘I / Ctrl+I - focus the input
  • Escape - blur the input
  • Enter - submit the question
Wrap it with Teleport and ClientOnly to ensure it renders correctly.
View source code

AiChatModelSelect

A model selection dropdown for switching AI models. Requires no props.

This component automatically displays the models list configured in nuxt.config.ts and uses the useModels composable to manage model state.
View source code

AiChatPanel

The complete AI chat panel interface.

Features:

  • An expandable/collapsible sidebar panel
  • Automatically pushes the main content area
  • Built-in message history and streaming responses
  • Supports code highlighting and Markdown rendering
View source code

AiChatDisabled

The disabled-state component shown when the AI Chat feature is not enabled.

View source code

Composables

useAIChat()

Conversation state management, providing state control and message management for the chat interface.

Return values

isOpen
Ref<boolean>
The reactive state of whether the dialog is open.
messages
Ref<UIMessage[]>
The message list, containing all conversation history.
open
(text: string) => void
Open the dialog and send an initial message.
toggleChat
() => void
Toggle the open/closed state of the dialog.

useModels()

Model configuration management, controlling the list of available AI models and the currently selected model.

Return values

models
Ref<string[]>
The list of available models, read from the aiChat.models configuration in nuxt.config.ts.
model
Ref<string>
The currently selected model ID, persisted to localStorage.
formatModelName
(modelId: string) => string
Format a model ID into a readable display name (removing the prefix and suffix).

useHighlighter()

Asynchronously loads a Shiki code highlighter instance, used for syntax highlighting of code blocks.

Return value

Returns a Promise that resolves to a configured Shiki Highlighter instance.

Supported languages:vue, js, ts, css, html, json, yaml, markdown, bashSupported themes:
  • material-theme-palenight (dark mode)
  • material-theme-lighter (light mode)
const highlighter = await useHighlighter()

// Usage example
const html = highlighter.codeToHtml(code, {
  lang: 'typescript',
  theme: 'material-theme-palenight'
})

useToolCall(state, toolName, input)

An extension point for AI chat tool calls, allowing you to customize the text label and icon shown when a tool is called.

When the AI assistant calls a tool, the AiChatPanel component calls this composable to get the display information for that tool. The default implementation returns an empty object, and the built-in tool labels are handled by the component itself. By overriding this composable in your application layer, you can add display support for custom tools.

Parameters

state
ToolState
The tool call state, used to determine whether it is complete: 'output-available' means complete, other values mean in progress.
toolName
string
The tool name, corresponding to the name field in the MCP tool definition.
input
Record<string, string | undefined>
The input parameters of the tool call.

Return values

toolMessage
Record<string, string>
A mapping from tool name to display text. The key is the tool name and the value is the corresponding display text. Unmatched tool names fall back to the default text.
toolIcon
Record<string, string>
A mapping from tool name to icon. The key is the tool name and the value is an Iconify icon name. Unmatched tool names fall back to i-lucide-search.

Extending with custom tools

Create a composable of the same name in your application layer to override the default implementation:

composables/useToolCall.ts
import type { ToolState } from '#ai-chat/types'

export function useToolCall(state: ToolState, toolName: string, input: Record<string, string | undefined>) {
  const searchVerb = state === 'output-available' ? 'Searched' : 'Searching'
  const readVerb = state === 'output-available' ? 'Read' : 'Reading'

  const toolMessage: Record<string, string> = {
    'search-api': `${searchVerb} the API docs`,
    'get-schema': `${readVerb} the ${input.name || ''} type definition`,
  }

  const toolIcon: Record<string, string> = {
    'search-api': 'i-lucide-book-open',
    'get-schema': 'i-lucide-braces',
  }

  return {
    toolMessage,
    toolIcon,
  }
}

Default handling of built-in tools

The following tools are handled internally by AiChatPanel and do not need to be defined in useToolCall. The default handling is tailored to the MCP tools built into the current project, and a single configuration generates both the display text and the icon:

Tool nameDisplay textIcon
search-documentationSearching / Searched documentation pages, optionally with section and search filtersi-lucide-book-search
search-composablesSearching / Searched composables, optionally with a search filteri-lucide-braces
search-iconsSearching / Searched icons, optionally with a query filteri-lucide-search
list-examplesSearching / Searched examplesi-lucide-codesandbox
get-documentation-pageReading / Read the {path} pagei-lucide-book-open
get-exampleReading / Read the {exampleName} examplei-lucide-codepen
get-componentReading / Read the {componentName} component docsi-lucide-box
get-component-metadataReading / Read the {componentName} component metadatai-lucide-file-code
Copyright © 2024 - 2026