Skip to content
Draft
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
2 changes: 2 additions & 0 deletions apps/docs/app/assets/css/main.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@import "tailwindcss";
@import "@nuxt/ui";

@source "../../../";

:root {
--ui-radius: 0;
--ui-bg: var(--color-white);
Expand Down
29 changes: 28 additions & 1 deletion apps/docs/app/components/DocsAsideRightBottom.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,33 @@ const route = useRoute()

const pageUrl = route.path
const { open } = useAIChat()

const faqQuestions = [
{
category: 'Getting Started',
items: [
'What is Nuxt MCP Toolkit?',
'How do I install the module?',
'How do I use the DevTools?',
],
},
{
category: 'Core Features',
items: [
'How do I create a new MCP Tool?',
'How do I add an MCP Resource?',
'How do I configure Prompts?',
],
},
{
category: 'Advanced',
items: [
'Can I expose my API routes as MCP Tools?',
'Does it support TypeScript?',
'How do I add a custom MCP server?',
],
},
]
</script>

<template>
Expand All @@ -16,6 +43,6 @@ const { open } = useAIChat()
color="neutral"
@click="open(`Explain the page ${pageUrl}`, true)"
/>
<AIChatSlideover />
<AiChatSlideover :faq-questions="faqQuestions" />
</div>
</template>
161 changes: 161 additions & 0 deletions apps/docs/modules/ai-chat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# AI Chat Module

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

## Features

- AI chat slideover component with streaming responses
- MCP tools integration for documentation search
- Syntax highlighting for code blocks
- FAQ suggestions
- Persistent chat state

## Installation

1. Copy the `modules/ai-chat` folder to your Nuxt project
2. Install the required dependencies:

```bash
pnpm add @ai-sdk/mcp @ai-sdk/vue @ai-sdk/gateway ai motion-v shiki shiki-stream
```

3. Add the module to your `nuxt.config.ts`:

```ts
export default defineNuxtConfig({
modules: ['./modules/ai-chat'],

aiChat: {
apiPath: '/api/ai-chat',
mcpPath: '/mcp',
model: 'moonshotai/kimi-k2-turbo',
}
})
```

## Usage

Add the components to your app:

```vue
<template>
<div>
<!-- Button to open the chat -->
<AiChat tooltip-text="Ask AI a question" />

<!-- Chat slideover (place once in your app/layout) -->
<AiChatSlideover
title="Ask AI"
placeholder="Ask a question..."
:faq-questions="faqQuestions"
/>
</div>
</template>

<script setup>
const faqQuestions = [
{
category: 'Getting Started',
items: ['How do I install?', 'How do I configure?'],
},
{
category: 'Advanced',
items: ['How do I customize?'],
},
]
</script>
```

### Programmatic Control

Use the `useAIChat` composable to control the chat:

```vue
<script setup>
const { open, close, toggle, isOpen, messages, clearMessages } = useAIChat()

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

// Open and clear previous messages
open('New question', true)

// Toggle chat visibility
toggle()

// Clear all messages
clearMessages()
</script>
```

## Module Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `apiPath` | `string` | `/api/ai-chat` | API endpoint path for the chat |
| `mcpPath` | `string` | `/mcp` | MCP server path to connect to |
| `model` | `string` | `moonshotai/kimi-k2-turbo` | AI model identifier for AI SDK Gateway |

## Component Props

### `<AiChat>`

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `tooltipText` | `string` | `Ask AI a question` | Tooltip text on hover |

### `<AiChatSlideover>`

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `title` | `string` | `Ask AI` | Title displayed in the header |
| `placeholder` | `string` | `Ask a question...` | Input placeholder text |
| `faqQuestions` | `FaqCategory[]` | `undefined` | FAQ categories to display when chat is empty |

#### FaqCategory Type

```ts
interface FaqCategory {
category: string
items: string[]
}
```

## Requirements

- Nuxt 4.x
- Nuxt UI 3.x (for `USlideover`, `UButton`, `UTextarea`, `UChatMessages`, etc.)
- An MCP server running (path configurable via `mcpPath`)
- AI SDK Gateway Key

## Components

- `AiChat` - Button to toggle the chat slideover
- `AiChatSlideover` - Main chat interface
- `AiChatToolCall` - Displays MCP tool invocations
- `AiChatPreStream` - Code block with streaming syntax highlighting

## Customization

### System Prompt

To customize the AI's behavior, edit the system prompt in:
`runtime/server/api/search.ts`

### Styling

The components use Nuxt UI and Tailwind CSS design tokens. Customize the appearance by modifying the component files or overriding the UI props.

## Dependencies

```json
{
"@ai-sdk/mcp": "^0.0.8",
"@ai-sdk/vue": "3.0.0-beta.105",
"@ai-sdk/gateway": "^1.0.0",
"ai": "6.0.0-beta.105",
"motion-v": "^1.7.4",
"shiki": "^3.0.0",
"shiki-stream": "^0.1.2"
}
```
86 changes: 86 additions & 0 deletions apps/docs/modules/ai-chat/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { addComponent, addImports, addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit'

export interface AiChatModuleOptions {
/**
* API endpoint path for the chat
* @default '/api/ai-chat'
*/
apiPath?: string
/**
* MCP server path to connect to
* @default '/mcp'
*/
mcpPath?: string
/**
* AI model to use via AI SDK Gateway
* @default 'moonshotai/kimi-k2-turbo'
*/
model?: string
}

export default defineNuxtModule<AiChatModuleOptions>({
meta: {
name: 'ai-chat',
configKey: 'aiChat',
},
defaults: {
apiPath: '/api/ai-chat',
mcpPath: '/mcp',
model: ' moonshotai/kimi-k2-turbo',
},
setup(options, nuxt) {
const { resolve } = createResolver(import.meta.url)

nuxt.options.runtimeConfig.public.aiChat = {
apiPath: options.apiPath!,
}
nuxt.options.runtimeConfig.aiChat = {
mcpPath: options.mcpPath!,
model: options.model!,
}

addComponent({
name: 'AiChat',
filePath: resolve('./runtime/components/AiChat.vue'),
})
addComponent({
name: 'AiChatSlideover',
filePath: resolve('./runtime/components/AiChatSlideover.vue'),
})
addComponent({
name: 'AiChatToolCall',
filePath: resolve('./runtime/components/AiChatToolCall.vue'),
})

addImports([
{
name: 'useAIChat',
from: resolve('./runtime/composables/useAIChat'),
},
{
name: 'useHighlighter',
from: resolve('./runtime/composables/useHighlighter'),
},
])

const routePath = options.apiPath!.replace(/^\//, '')
addServerHandler({
route: `/${routePath}`,
handler: resolve('./runtime/server/api/search'),
})
},
})

declare module 'nuxt/schema' {
interface PublicRuntimeConfig {
aiChat: {
apiPath: string
}
}
interface RuntimeConfig {
aiChat: {
mcpPath: string
model: string
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
<script setup lang="ts">
withDefaults(defineProps<{
tooltipText?: string
}>(), {
tooltipText: 'Ask AI a question',
})

const { toggle } = useAIChat()
</script>

<template>
<UTooltip text="Ask AI a question">
<UTooltip :text="tooltipText">
<UButton
icon="i-lucide-sparkles"
variant="ghost"
Expand Down
Loading
Loading