diff --git a/packages/website/src/components/DocsSidebar.astro b/packages/website/src/components/DocsSidebar.astro index 1215a27..6f2788b 100644 --- a/packages/website/src/components/DocsSidebar.astro +++ b/packages/website/src/components/DocsSidebar.astro @@ -7,7 +7,7 @@ const { currentPath } = Astro.props; const navigation = [ { - title: '开始', + title: '入门指南', items: [ { title: '概览', href: '/docs' }, { title: '快速开始', href: '/docs/quickstart' }, @@ -19,9 +19,9 @@ const navigation = [ items: [ { title: 'Agent 系统', href: '/docs/core/agent' }, { title: '工具系统', href: '/docs/core/tools' }, - { title: '编辑模式', href: '/docs/features/edit-modes' }, - { title: 'Checkpoint 系统', href: '/docs/features/checkpoint' }, - { title: '会话管理', href: '/docs/features/chat-history' }, + { title: '编辑模式', href: '/docs/core/edit-modes' }, + { title: 'Checkpoint', href: '/docs/core/checkpoint' }, + { title: '会话管理', href: '/docs/core/session' }, { title: 'MCP 集成', href: '/docs/core/mcp' }, ], }, @@ -34,21 +34,27 @@ const navigation = [ ], }, { - title: '更多功能', + title: '部署与配置', items: [ - { title: '多模型支持', href: '/docs/features/multi-model' }, - { title: '仓库地图', href: '/docs/features/repo-map' }, - { title: '浏览器 GUI', href: '/docs/features/browser-gui' }, - { title: '配置管理', href: '/docs/features/configuration' }, + { title: '配置管理', href: '/docs/deploy/configuration' }, + { title: '本地部署', href: '/docs/deploy/local' }, + { title: '生产部署', href: '/docs/deploy/production' }, ], }, { - title: '规划中', + title: '客户端', items: [ - { title: 'Linting 集成', href: '/docs/features/linting' }, - { title: '测试集成', href: '/docs/features/testing' }, - { title: 'Watch 模式', href: '/docs/features/watch-mode' }, - { title: '语音输入', href: '/docs/features/voice-input' }, + { title: 'Web 前端', href: '/docs/clients/web' }, + { title: '桌面应用', href: '/docs/clients/desktop' }, + { title: 'CLI 命令', href: '/docs/clients/cli' }, + ], + }, + { + title: '扩展开发', + items: [ + { title: '自定义工具', href: '/docs/extend/custom-tools' }, + { title: 'Hooks 系统', href: '/docs/extend/hooks' }, + { title: 'MCP 服务器', href: '/docs/extend/mcp-server' }, ], }, ]; diff --git a/packages/website/src/pages/docs/clients/cli.astro b/packages/website/src/pages/docs/clients/cli.astro new file mode 100644 index 0000000..908a596 --- /dev/null +++ b/packages/website/src/pages/docs/clients/cli.astro @@ -0,0 +1,327 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

CLI 命令

+ +

+ CLI 提供命令行界面,支持启动服务器和连接到远程服务器进行交互式对话。 +

+ +

安装

+ +
# 全局安装
+npm install -g @ai-assistant/cli
+
+# 或使用 pnpm
+pnpm add -g @ai-assistant/cli
+
+# 验证安装
+ai-assistant --version
+ +

命令概览

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
命令说明示例
serve启动 HTTP 服务器ai-assistant serve
attach连接到服务器ai-assistant attach http://localhost:3000
--help显示帮助信息ai-assistant --help
--version显示版本号ai-assistant --version
+ +

serve 命令

+ +

启动 AI Assistant HTTP 服务器,提供 REST API 和 WebSocket 接口。

+ +
ai-assistant serve [选项]
+ +

选项

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
选项说明默认值
-p, --port <port>服务器端口3000
-h, --host <host>监听地址localhost
-d, --dir <path>工作目录当前目录
--auth启用认证非 localhost 时自动启用
--token <token>指定认证 Token自动生成
+ +

示例

+ +
# 基本启动
+ai-assistant serve
+
+# 指定端口和目录
+ai-assistant serve --port 8080 --dir /path/to/project
+
+# 远程访问模式
+ai-assistant serve --host 0.0.0.0 --port 3000
+
+# 指定认证 Token
+ai-assistant serve --auth --token my-secret-token
+ +

输出示例

+ +
🚀 AI Terminal Assistant Server
+
+   Local:   http://localhost:3000
+   Network: http://192.168.1.100:3000
+
+   Auth:    Enabled
+   Token:   abc123...xyz789
+
+   Working Directory: /Users/dev/project
+
+   Press Ctrl+C to stop
+ +

attach 命令

+ +

连接到运行中的 AI Assistant 服务器,进行交互式对话。

+ +
ai-assistant attach <url> [选项]
+ +

选项

+ + + + + + + + + + + + + + + + + + + + + +
选项说明默认值
-t, --token <token>认证 Token-
-s, --session <id>指定会话 ID自动创建
+ +

示例

+ +
# 连接本地服务器
+ai-assistant attach http://localhost:3000
+
+# 连接远程服务器(带认证)
+ai-assistant attach https://ai.example.com --token your-token
+
+# 恢复已有会话
+ai-assistant attach http://localhost:3000 --session session-123
+ +

交互式界面

+ +
✓ Connected to http://localhost:3000
+  Session: session-abc123
+
+You: 帮我分析这个项目的结构
+
+AI: 我来分析这个项目的结构...
+
+[调用工具: list_directory]
+路径: /Users/dev/project
+
+项目结构如下:
+├── src/
+│   ├── index.ts
+│   └── utils/
+├── package.json
+└── README.md
+
+这是一个 TypeScript 项目...
+
+You: _
+ +

交互式命令

+ +

在 attach 模式下,支持以下交互式命令:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
命令说明
/exit/quit退出交互
/clear清空当前会话历史
/new创建新会话
/sessions列出所有会话
/switch <id>切换到指定会话
/status显示连接状态
/help显示帮助信息
+ +

环境变量

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
变量说明命令
ANTHROPIC_API_KEYAnthropic API Keyserve
AI_ASSISTANT_TOKEN默认认证 Tokenattach
AI_ASSISTANT_URL默认服务器地址attach
+ +
# 设置环境变量
+export ANTHROPIC_API_KEY=sk-ant-...
+export AI_ASSISTANT_TOKEN=my-token
+export AI_ASSISTANT_URL=http://localhost:3000
+
+# 使用环境变量(无需每次指定)
+ai-assistant attach
+ +

配置文件

+ +

可以在 ~/.ai-assistant/config.json 中配置默认选项:

+ +
{
+  "defaultServer": "http://localhost:3000",
+  "defaultToken": "your-token",
+  "theme": "dark",
+  "historySize": 1000,
+  "autoConnect": true
+}
+ +

开发模式运行

+ +

在项目开发中直接运行:

+ +
# 使用 bun 运行
+cd packages/cli
+bun run src/index.ts serve --port 3000
+
+# 或使用 tsx
+npx tsx src/index.ts attach http://localhost:3000
+ +

退出码

+ + + + + + + + + + + + + + +
退出码说明
0正常退出
1一般错误
2连接失败
3认证失败
+ +

相关文档

+ +
+ +

本地部署

+

本地开发环境搭建

+
+ + +

REST API

+

API 端点文档

+
+
+
diff --git a/packages/website/src/pages/docs/clients/desktop.astro b/packages/website/src/pages/docs/clients/desktop.astro new file mode 100644 index 0000000..68ba104 --- /dev/null +++ b/packages/website/src/pages/docs/clients/desktop.astro @@ -0,0 +1,287 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

桌面应用

+ +

🚧 开发中 - 基础功能已实现

+ +

+ 桌面应用基于 Tauri 构建,提供原生桌面体验,支持 Windows、macOS 和 Linux。 + 复用 Web 前端代码,结合 Rust 后端提供更好的性能和系统集成。 +

+ +

功能特性

+ + + +

系统要求

+ +

开发环境

+ + + +

平台依赖

+ +
# macOS
+xcode-select --install
+
+# Ubuntu/Debian
+sudo apt install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
+
+# Windows
+# 需要安装 Visual Studio C++ Build Tools
+ +

快速开始

+ +

开发模式

+ +
# 进入 desktop 包目录
+cd packages/desktop
+
+# 安装依赖
+pnpm install
+
+# 启动开发模式
+pnpm tauri dev
+ +

构建发布版本

+ +
# 构建当前平台
+pnpm tauri build
+
+# 输出目录:
+# - macOS: src-tauri/target/release/bundle/dmg/
+# - Windows: src-tauri/target/release/bundle/msi/
+# - Linux: src-tauri/target/release/bundle/deb/
+ +

项目结构

+ +
packages/desktop/
+├── src/                 # 前端代码 (复用 web)
+├── src-tauri/           # Tauri/Rust 后端
+│   ├── src/
+│   │   ├── main.rs      # 应用入口
+│   │   ├── commands.rs  # Tauri 命令
+│   │   ├── tray.rs      # 系统托盘
+│   │   └── window.rs    # 窗口管理
+│   ├── icons/           # 应用图标
+│   ├── tauri.conf.json  # Tauri 配置
+│   └── Cargo.toml       # Rust 依赖
+├── index.html
+└── vite.config.ts
+ +

Tauri 配置

+ +
// src-tauri/tauri.conf.json
+{
+  "productName": "AI Terminal Assistant",
+  "version": "0.1.0",
+  "identifier": "com.ai-assistant.app",
+  "build": {
+    "beforeDevCommand": "pnpm dev",
+    "beforeBuildCommand": "pnpm build",
+    "devPath": "http://localhost:5173",
+    "distDir": "../dist"
+  },
+  "app": {
+    "windows": [
+      {
+        "title": "AI Terminal Assistant",
+        "width": 1200,
+        "height": 800,
+        "resizable": true,
+        "fullscreen": false
+      }
+    ],
+    "security": {
+      "csp": null
+    }
+  },
+  "bundle": {
+    "active": true,
+    "targets": "all",
+    "icon": [
+      "icons/32x32.png",
+      "icons/128x128.png",
+      "icons/icon.icns",
+      "icons/icon.ico"
+    ]
+  }
+}
+ +

Tauri 命令

+ +

在 Rust 中定义可从前端调用的命令:

+ +
// src-tauri/src/commands.rs
+use tauri::command;
+
+#[command]
+pub fn get_system_info() -> Result<SystemInfo, String> {
+    Ok(SystemInfo {
+        os: std::env::consts::OS.to_string(),
+        arch: std::env::consts::ARCH.to_string(),
+    })
+}
+
+#[command]
+pub async fn open_project(path: String) -> Result<(), String> {
+    // 打开项目目录
+    std::env::set_current_dir(&path)
+        .map_err(|e| e.to_string())
+}
+ +

在前端调用:

+ +
import { invoke } from '@tauri-apps/api/core';
+
+// 调用 Rust 命令
+const info = await invoke('get_system_info');
+console.log('系统信息:', info);
+
+// 打开项目
+await invoke('open_project', { path: '/path/to/project' });
+ +

系统托盘

+ +
// src-tauri/src/tray.rs
+use tauri::{
+    tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
+    Manager,
+};
+
+pub fn create_tray(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
+    let tray = TrayIconBuilder::new()
+        .icon(app.default_window_icon().unwrap().clone())
+        .tooltip("AI Terminal Assistant")
+        .on_tray_icon_event(|tray, event| {
+            if let TrayIconEvent::Click {
+                button: MouseButton::Left,
+                button_state: MouseButtonState::Up,
+                ..
+            } = event
+            {
+                let app = tray.app_handle();
+                if let Some(window) = app.get_webview_window("main") {
+                    let _ = window.show();
+                    let _ = window.set_focus();
+                }
+            }
+        })
+        .build(app)?;
+
+    Ok(())
+}
+ +

快捷键

+ +
use tauri::Manager;
+
+fn setup_shortcuts(app: &tauri::App) {
+    use tauri_plugin_global_shortcut::GlobalShortcutExt;
+
+    app.handle().plugin(
+        tauri_plugin_global_shortcut::Builder::new()
+            .with_shortcuts(["ctrl+shift+a"])?
+            .with_handler(|app, shortcut, event| {
+                if shortcut.matches(Modifiers::CONTROL | Modifiers::SHIFT, Code::KeyA) {
+                    // 显示/隐藏窗口
+                    if let Some(window) = app.get_webview_window("main") {
+                        if window.is_visible().unwrap_or(false) {
+                            let _ = window.hide();
+                        } else {
+                            let _ = window.show();
+                            let _ = window.set_focus();
+                        }
+                    }
+                }
+            })
+            .build()
+    )?;
+}
+ +

文件系统访问

+ +
import { open, save } from '@tauri-apps/plugin-dialog';
+import { readTextFile, writeTextFile } from '@tauri-apps/plugin-fs';
+
+// 打开文件选择对话框
+const selected = await open({
+  multiple: false,
+  filters: [{ name: 'Text', extensions: ['txt', 'md'] }]
+});
+
+if (selected) {
+  const content = await readTextFile(selected);
+  console.log('文件内容:', content);
+}
+
+// 保存文件
+const savePath = await save({
+  filters: [{ name: 'Markdown', extensions: ['md'] }]
+});
+
+if (savePath) {
+  await writeTextFile(savePath, '# Hello World');
+}
+ +

自动更新

+ +
// tauri.conf.json
+{
+  "plugins": {
+    "updater": {
+      "active": true,
+      "endpoints": [
+        "https://releases.example.com/{{target}}/{{arch}}/{{current_version}}"
+      ],
+      "pubkey": "YOUR_PUBLIC_KEY"
+    }
+  }
+}
+ +
import { check } from '@tauri-apps/plugin-updater';
+
+async function checkForUpdates() {
+  const update = await check();
+  if (update?.available) {
+    console.log(`发现新版本: ${update.version}`);
+    await update.downloadAndInstall();
+  }
+}
+ +

开发注意事项

+ + + +

相关文档

+ +
+ +

Web 前端

+

React Web 客户端

+
+ + +

Tauri 官方文档 ↗

+

Tauri 框架文档

+
+
+
diff --git a/packages/website/src/pages/docs/clients/web.astro b/packages/website/src/pages/docs/clients/web.astro new file mode 100644 index 0000000..b46f0c8 --- /dev/null +++ b/packages/website/src/pages/docs/clients/web.astro @@ -0,0 +1,253 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

Web 前端

+ +

+ Web 前端是基于 React + Vite 构建的现代化 Web 应用,提供完整的 AI 对话交互界面。 +

+ +

功能特性

+ + + +

快速开始

+ +

开发模式

+ +
# 进入 web 包目录
+cd packages/web
+
+# 安装依赖
+pnpm install
+
+# 启动开发服务器
+pnpm dev
+
+# 访问 http://localhost:5173
+ +

生产构建

+ +
# 构建生产版本
+pnpm build
+
+# 预览构建结果
+pnpm preview
+
+# 输出目录: dist/
+ +

环境配置

+ +

.env.env.local 中配置:

+ +
# API 服务器地址
+VITE_API_URL=http://localhost:3000
+
+# WebSocket 地址(可选,默认从 API_URL 推导)
+VITE_WS_URL=ws://localhost:3000
+
+# 认证 Token(远程连接时需要)
+VITE_AUTH_TOKEN=your-auth-token
+ +

项目结构

+ +
packages/web/
+├── src/
+│   ├── components/      # React 组件
+│   │   ├── Chat/        # 聊天相关组件
+│   │   ├── Message/     # 消息显示组件
+│   │   ├── Tool/        # 工具调用显示
+│   │   └── Layout/      # 布局组件
+│   ├── hooks/           # 自定义 Hooks
+│   │   ├── useWebSocket.ts
+│   │   ├── useSession.ts
+│   │   └── usePermission.ts
+│   ├── services/        # API 服务
+│   │   ├── api.ts       # REST API 客户端
+│   │   └── websocket.ts # WebSocket 客户端
+│   ├── stores/          # 状态管理
+│   ├── types/           # TypeScript 类型
+│   ├── App.tsx          # 应用入口
+│   └── main.tsx         # 渲染入口
+├── public/              # 静态资源
+├── index.html           # HTML 模板
+└── vite.config.ts       # Vite 配置
+ +

核心组件

+ +

ChatContainer

+ +

主聊天容器,管理消息列表和输入:

+ +
import { ChatContainer } from '@/components/Chat';
+
+function App() {
+  return (
+    <ChatContainer
+      sessionId="session-123"
+      onMessage={(msg) => console.log(msg)}
+    />
+  );
+}
+ +

MessageList

+ +

消息列表组件,支持多种消息类型:

+ +
import { MessageList } from '@/components/Message';
+
+<MessageList
+  messages={messages}
+  onToolApprove={handleToolApprove}
+  onToolReject={handleToolReject}
+/>
+ +

ToolCallDisplay

+ +

工具调用展示组件:

+ +
import { ToolCallDisplay } from '@/components/Tool';
+
+<ToolCallDisplay
+  tool={{
+    name: 'read_file',
+    params: { path: '/src/index.ts' },
+    status: 'completed',
+    result: '文件内容...'
+  }}
+/>
+ +

WebSocket 集成

+ +
import { useWebSocket } from '@/hooks/useWebSocket';
+
+function ChatComponent() {
+  const {
+    connected,
+    send,
+    lastMessage,
+    disconnect
+  } = useWebSocket(sessionId);
+
+  const handleSend = (content: string) => {
+    send({
+      type: 'message',
+      payload: { content }
+    });
+  };
+
+  // 处理接收的消息
+  useEffect(() => {
+    if (lastMessage) {
+      switch (lastMessage.type) {
+        case 'chunk':
+          appendContent(lastMessage.payload.content);
+          break;
+        case 'tool_call':
+          showToolCall(lastMessage.payload);
+          break;
+        case 'done':
+          finishMessage();
+          break;
+      }
+    }
+  }, [lastMessage]);
+}
+ +

状态管理

+ +

使用 Zustand 进行状态管理:

+ +
import { create } from 'zustand';
+
+interface ChatStore {
+  messages: Message[];
+  currentSession: string | null;
+  addMessage: (msg: Message) => void;
+  setSession: (id: string) => void;
+}
+
+export const useChatStore = create<ChatStore>((set) => ({
+  messages: [],
+  currentSession: null,
+  addMessage: (msg) => set((state) => ({
+    messages: [...state.messages, msg]
+  })),
+  setSession: (id) => set({ currentSession: id })
+}));
+ +

主题定制

+ +

使用 Tailwind CSS 自定义主题:

+ +
// tailwind.config.js
+export default {
+  theme: {
+    extend: {
+      colors: {
+        primary: {
+          50: '#f0f9ff',
+          // ...
+          900: '#0c4a6e',
+        },
+        background: '#0a0a0a',
+        surface: '#1a1a1a',
+      },
+      fontFamily: {
+        mono: ['JetBrains Mono', 'monospace'],
+      },
+    },
+  },
+};
+ +

部署

+ +

静态部署

+ +
# 构建
+VITE_API_URL=https://api.example.com pnpm build
+
+# 部署 dist/ 目录到任何静态托管服务
+# - Vercel
+# - Netlify
+# - Cloudflare Pages
+# - Nginx
+ +

Docker 部署

+ +
# Dockerfile.web
+FROM node:20-alpine as builder
+WORKDIR /app
+COPY . .
+RUN npm install -g pnpm
+RUN pnpm install
+RUN pnpm --filter @ai-assistant/web build
+
+FROM nginx:alpine
+COPY --from=builder /app/packages/web/dist /usr/share/nginx/html
+COPY nginx.conf /etc/nginx/conf.d/default.conf
+EXPOSE 80
+ +

相关文档

+ +
+ +

WebSocket API

+

实时通信协议

+
+ + +

桌面应用

+

Tauri 桌面客户端

+
+
+
diff --git a/packages/website/src/pages/docs/features/checkpoint.astro b/packages/website/src/pages/docs/core/checkpoint.astro similarity index 100% rename from packages/website/src/pages/docs/features/checkpoint.astro rename to packages/website/src/pages/docs/core/checkpoint.astro diff --git a/packages/website/src/pages/docs/features/edit-modes.astro b/packages/website/src/pages/docs/core/edit-modes.astro similarity index 100% rename from packages/website/src/pages/docs/features/edit-modes.astro rename to packages/website/src/pages/docs/core/edit-modes.astro diff --git a/packages/website/src/pages/docs/features/chat-history.astro b/packages/website/src/pages/docs/core/session.astro similarity index 100% rename from packages/website/src/pages/docs/features/chat-history.astro rename to packages/website/src/pages/docs/core/session.astro diff --git a/packages/website/src/pages/docs/deploy/configuration.astro b/packages/website/src/pages/docs/deploy/configuration.astro new file mode 100644 index 0000000..c3de481 --- /dev/null +++ b/packages/website/src/pages/docs/deploy/configuration.astro @@ -0,0 +1,215 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

配置管理

+ +

+ AI Terminal Assistant 支持多层配置系统,可以通过环境变量、配置文件等方式进行配置。 +

+ +

环境变量

+ +

必需配置

+ + + + + + + + + + + + + + + + +
变量名说明示例
ANTHROPIC_API_KEYAnthropic API 密钥sk-ant-...
+ +

可选配置

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
变量名说明默认值
OPENAI_API_KEYOpenAI API 密钥-
DEEPSEEK_API_KEYDeepSeek API 密钥-
TAVILY_API_KEYTavily 搜索 API 密钥-
AI_MODEL默认模型claude-sonnet-4-20250514
AI_MAX_TOKENS最大输出 tokens4096
AI_TEMPERATURE温度参数0.7
+ +

配置文件

+ +

.env 文件

+ +
# .env 文件示例
+ANTHROPIC_API_KEY=sk-ant-your-key-here
+OPENAI_API_KEY=sk-your-openai-key
+TAVILY_API_KEY=tvly-your-tavily-key
+
+# 模型配置
+AI_MODEL=claude-sonnet-4-20250514
+AI_MAX_TOKENS=8192
+AI_TEMPERATURE=0.7
+ +

项目配置文件

+ +

在项目根目录创建 .ai-assistant/config.json

+ +
{
+  "model": "claude-sonnet-4-20250514",
+  "maxTokens": 4096,
+  "temperature": 0.7,
+  "systemPrompt": "你是一个专业的编程助手",
+  "tools": {
+    "enabled": ["read_file", "write_file", "bash", "grep"],
+    "disabled": ["web_search"]
+  },
+  "permissions": {
+    "allowedPaths": ["/project"],
+    "deniedPaths": ["/project/secrets"],
+    "autoApprove": ["read_file", "grep"]
+  }
+}
+ +

MCP 服务器配置

+ +

在项目根目录创建 mcp.json

+ +
{
+  "mcpServers": {
+    "filesystem": {
+      "command": "npx",
+      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
+      "env": {}
+    },
+    "github": {
+      "command": "npx",
+      "args": ["-y", "@modelcontextprotocol/server-github"],
+      "env": {
+        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
+      }
+    }
+  }
+}
+ +

配置优先级

+ +

配置按以下优先级加载(高 → 低):

+ +
    +
  1. 命令行参数
  2. +
  3. 环境变量
  4. +
  5. 项目配置文件 (.ai-assistant/config.json)
  6. +
  7. 用户配置文件 (~/.config/ai-assistant/config.json)
  8. +
  9. 默认值
  10. +
+ +

服务器配置

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
参数环境变量说明默认值
--portPORT服务器端口3000
--hostHOST绑定地址127.0.0.1
--authAUTH_ENABLED启用认证远程模式自动启用
--tokenAUTH_TOKEN认证 Token自动生成
+ +

权限配置

+ +
interface PermissionConfig {
+  // 允许访问的路径
+  allowedPaths: string[];
+
+  // 禁止访问的路径
+  deniedPaths: string[];
+
+  // 自动批准的工具
+  autoApprove: string[];
+
+  // 禁用的工具
+  disabledTools: string[];
+
+  // 允许执行的 Shell 命令模式
+  shellPatterns: string[];
+}
+ +

相关文档

+ +
+ +

本地部署

+

开发环境搭建指南

+
+ + +

生产部署

+

服务器和容器部署

+
+
+
diff --git a/packages/website/src/pages/docs/deploy/local.astro b/packages/website/src/pages/docs/deploy/local.astro new file mode 100644 index 0000000..7d69590 --- /dev/null +++ b/packages/website/src/pages/docs/deploy/local.astro @@ -0,0 +1,208 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

本地部署

+ +

+ 本指南介绍如何在本地搭建 AI Terminal Assistant 开发环境。 +

+ +

系统要求

+ + + +

可选依赖

+ + + +

安装步骤

+ +

1. 克隆仓库

+ +
git clone https://github.com/your-username/ai-terminal-assistant.git
+cd ai-terminal-assistant
+ +

2. 安装依赖

+ +
# 使用 pnpm 安装所有依赖
+pnpm install
+ +

3. 配置环境变量

+ +
# 复制环境变量模板
+cp .env.example .env
+
+# 编辑 .env 文件,添加 API 密钥
+# ANTHROPIC_API_KEY=your-api-key
+ +

4. 构建项目

+ +
# 构建核心包
+pnpm --filter @ai-assistant/core build
+
+# 构建服务器
+pnpm --filter @ai-assistant/server build
+
+# 或一次性构建所有包
+pnpm build
+ +

启动开发服务器

+ +

方式一:分开启动

+ +
# 终端 1:启动 HTTP 服务器
+pnpm server:dev
+
+# 终端 2:启动 Web 前端
+cd packages/web && pnpm dev
+ +

然后访问 http://localhost:5173

+ +

方式二:使用 CLI

+ +
# 启动服务器
+cd packages/cli
+bun run src/index.ts serve --port 3000
+ +

开发命令

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
命令说明
pnpm build构建所有包
pnpm test运行所有测试
pnpm --filter @ai-assistant/core build只构建 core 包
pnpm --filter @ai-assistant/core test:watch监视模式运行 core 测试
pnpm server:dev开发模式启动服务器
+ +

项目结构

+ +
ai-terminal-assistant/
+├── packages/
+│   ├── core/           # 核心引擎
+│   │   ├── src/
+│   │   │   ├── core/       # Agent 系统
+│   │   │   ├── tools/      # 工具注册
+│   │   │   ├── editors/    # 编辑器
+│   │   │   ├── checkpoint/ # 检查点
+│   │   │   ├── mcp/        # MCP 客户端
+│   │   │   └── lsp/        # LSP 集成
+│   │   └── package.json
+│   │
+│   ├── server/         # HTTP 服务器
+│   │   ├── src/
+│   │   │   ├── routes/     # API 路由
+│   │   │   ├── ws.ts       # WebSocket
+│   │   │   └── sse.ts      # SSE
+│   │   └── package.json
+│   │
+│   ├── cli/            # 命令行工具
+│   ├── web/            # React 前端
+│   └── desktop/        # Tauri 桌面应用
+│
+├── docs/               # 设计文档
+├── pnpm-workspace.yaml
+└── package.json
+ +

调试技巧

+ +

查看 Agent 日志

+ +
# 启用详细日志
+DEBUG=ai-assistant:* pnpm server:dev
+ +

测试单个工具

+ +
import { toolRegistry } from '@ai-assistant/core/tools';
+
+// 获取工具
+const readFile = toolRegistry.get('read_file');
+
+// 执行测试
+const result = await readFile.execute({
+  path: '/path/to/file.ts'
+});
+
+console.log(result);
+ +

VS Code 调试配置

+ +
// .vscode/launch.json
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Debug Server",
+      "type": "node",
+      "request": "launch",
+      "runtimeExecutable": "bun",
+      "runtimeArgs": ["run"],
+      "program": "${workspaceFolder}/packages/server/src/bin/server.ts",
+      "cwd": "${workspaceFolder}"
+    }
+  ]
+}
+ +

常见问题

+ +

依赖安装失败

+ +
# 清理缓存重新安装
+rm -rf node_modules pnpm-lock.yaml
+pnpm store prune
+pnpm install
+ +

端口被占用

+ +
# 查找占用端口的进程
+lsof -i :3000
+
+# 使用其他端口
+pnpm server:dev -- --port 3001
+ +

相关文档

+ +
+ +

配置管理

+

环境变量和配置文件

+
+ + +

生产部署

+

Docker 和服务器部署

+
+
+
diff --git a/packages/website/src/pages/docs/deploy/production.astro b/packages/website/src/pages/docs/deploy/production.astro new file mode 100644 index 0000000..3a51818 --- /dev/null +++ b/packages/website/src/pages/docs/deploy/production.astro @@ -0,0 +1,271 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

生产部署

+ +

+ 本指南介绍如何将 AI Terminal Assistant 部署到生产环境。 +

+ +

部署方式

+ + + +

Docker 部署

+ +

Dockerfile

+ +
# Dockerfile
+FROM oven/bun:1 as builder
+
+WORKDIR /app
+COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
+COPY packages ./packages
+
+RUN npm install -g pnpm
+RUN pnpm install --frozen-lockfile
+RUN pnpm build
+
+# 生产镜像
+FROM oven/bun:1-slim
+
+WORKDIR /app
+COPY --from=builder /app/packages/server/dist ./dist
+COPY --from=builder /app/packages/core/dist ./core
+COPY --from=builder /app/node_modules ./node_modules
+
+ENV NODE_ENV=production
+ENV PORT=3000
+
+EXPOSE 3000
+
+CMD ["bun", "run", "dist/bin/server.js"]
+ +

Docker Compose

+ +
# docker-compose.yml
+version: '3.8'
+
+services:
+  ai-assistant:
+    build: .
+    ports:
+      - "3000:3000"
+    environment:
+      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
+      - HOST=0.0.0.0
+      - PORT=3000
+      - AUTH_ENABLED=true
+      - AUTH_TOKEN=${AUTH_TOKEN}
+    volumes:
+      - ./projects:/projects:rw
+    restart: unless-stopped
+
+  web:
+    build:
+      context: .
+      dockerfile: Dockerfile.web
+    ports:
+      - "80:80"
+    depends_on:
+      - ai-assistant
+    restart: unless-stopped
+ +

运行容器

+ +
# 构建镜像
+docker build -t ai-assistant .
+
+# 运行容器
+docker run -d \
+  --name ai-assistant \
+  -p 3000:3000 \
+  -e ANTHROPIC_API_KEY=your-key \
+  -e AUTH_TOKEN=your-secret-token \
+  -v /path/to/projects:/projects \
+  ai-assistant
+
+# 使用 Docker Compose
+docker-compose up -d
+ +

直接部署

+ +

系统服务 (systemd)

+ +
# /etc/systemd/system/ai-assistant.service
+[Unit]
+Description=AI Terminal Assistant
+After=network.target
+
+[Service]
+Type=simple
+User=ai-assistant
+WorkingDirectory=/opt/ai-assistant
+ExecStart=/usr/local/bin/bun run dist/bin/server.js
+Restart=on-failure
+RestartSec=10
+Environment=NODE_ENV=production
+Environment=PORT=3000
+Environment=HOST=0.0.0.0
+EnvironmentFile=/opt/ai-assistant/.env
+
+[Install]
+WantedBy=multi-user.target
+ +
# 启用并启动服务
+sudo systemctl enable ai-assistant
+sudo systemctl start ai-assistant
+
+# 查看状态
+sudo systemctl status ai-assistant
+
+# 查看日志
+sudo journalctl -u ai-assistant -f
+ +

PM2 部署

+ +
// ecosystem.config.js
+module.exports = {
+  apps: [{
+    name: 'ai-assistant',
+    script: 'dist/bin/server.js',
+    interpreter: 'bun',
+    cwd: '/opt/ai-assistant',
+    env: {
+      NODE_ENV: 'production',
+      PORT: 3000,
+      HOST: '0.0.0.0'
+    },
+    env_file: '.env',
+    instances: 1,
+    autorestart: true,
+    watch: false,
+    max_memory_restart: '1G'
+  }]
+};
+ +
# 启动
+pm2 start ecosystem.config.js
+
+# 保存并开机启动
+pm2 save
+pm2 startup
+ +

Nginx 反向代理

+ +
# /etc/nginx/sites-available/ai-assistant
+server {
+    listen 80;
+    server_name your-domain.com;
+
+    # 重定向到 HTTPS
+    return 301 https://$server_name$request_uri;
+}
+
+server {
+    listen 443 ssl http2;
+    server_name your-domain.com;
+
+    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
+    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
+
+    # API 和 WebSocket
+    location /api/ {
+        proxy_pass http://127.0.0.1:3000;
+        proxy_http_version 1.1;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+
+        # WebSocket 超时
+        proxy_read_timeout 86400s;
+        proxy_send_timeout 86400s;
+    }
+
+    # 静态文件
+    location / {
+        root /var/www/ai-assistant;
+        try_files $uri $uri/ /index.html;
+    }
+}
+ +

Web 前端静态部署

+ +

构建静态文件

+ +
# 设置 API 地址
+echo "VITE_API_URL=https://api.your-domain.com" > packages/web/.env.production
+
+# 构建
+cd packages/web && pnpm build
+
+# 输出在 dist/ 目录
+ +

Vercel 部署

+ +
// vercel.json
+{
+  "buildCommand": "cd packages/web && pnpm build",
+  "outputDirectory": "packages/web/dist",
+  "framework": "vite",
+  "rewrites": [
+    { "source": "/(.*)", "destination": "/index.html" }
+  ]
+}
+ +

安全配置

+ +

HTTPS 证书

+ +
# 使用 Let's Encrypt
+sudo certbot --nginx -d your-domain.com
+ +

防火墙

+ +
# UFW
+sudo ufw allow 80/tcp
+sudo ufw allow 443/tcp
+sudo ufw enable
+ +

认证配置

+ +
# 生成强 Token
+openssl rand -hex 32
+
+# 设置环境变量
+export AUTH_TOKEN=your-generated-token
+ +

监控与日志

+ +
# 健康检查
+curl https://your-domain.com/health
+
+# 查看容器日志
+docker logs -f ai-assistant
+
+# 查看系统服务日志
+journalctl -u ai-assistant -f
+ +

相关文档

+ +
+ +

配置管理

+

环境变量和配置文件

+
+ + +

REST API

+

API 端点文档

+
+
+
diff --git a/packages/website/src/pages/docs/extend/custom-tools.astro b/packages/website/src/pages/docs/extend/custom-tools.astro new file mode 100644 index 0000000..a0577d5 --- /dev/null +++ b/packages/website/src/pages/docs/extend/custom-tools.astro @@ -0,0 +1,300 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

自定义工具

+ +

+ 工具是 AI Agent 与外部世界交互的方式。你可以创建自定义工具来扩展 AI 的能力, + 例如访问数据库、调用 API、执行特定业务逻辑等。 +

+ +

工具结构

+ +

每个工具需要定义以下属性:

+ +
interface Tool {
+  name: string;           // 工具名称(唯一标识)
+  description: string;    // 工具描述(AI 用于判断何时使用)
+  parameters: ZodSchema;  // 参数 Schema(Zod 定义)
+  execute: (params: T, context: ToolContext) => Promise<ToolResult>;
+}
+ +

基本示例

+ +
import { z } from 'zod';
+import { toolRegistry } from '@ai-assistant/core';
+
+// 定义参数 Schema
+const weatherParams = z.object({
+  city: z.string().describe('城市名称'),
+  units: z.enum(['celsius', 'fahrenheit']).default('celsius')
+});
+
+// 注册工具
+toolRegistry.register({
+  name: 'get_weather',
+  description: '获取指定城市的天气信息',
+  parameters: weatherParams,
+  execute: async (params) => {
+    const { city, units } = params;
+
+    // 调用天气 API
+    const response = await fetch(
+      `https://api.weather.com/v1/current?city=${city}&units=${units}`
+    );
+    const data = await response.json();
+
+    return {
+      success: true,
+      result: `${city} 当前温度: ${data.temperature}°${units === 'celsius' ? 'C' : 'F'}`
+    };
+  }
+});
+ +

工具上下文

+ +

ToolContext 提供执行环境信息:

+ +
interface ToolContext {
+  workDir: string;          // 当前工作目录
+  sessionId: string;        // 当前会话 ID
+  abortSignal?: AbortSignal; // 取消信号
+  agent: Agent;             // Agent 实例
+}
+
+toolRegistry.register({
+  name: 'list_project_files',
+  description: '列出项目中的文件',
+  parameters: z.object({
+    pattern: z.string().optional()
+  }),
+  execute: async (params, context) => {
+    const { workDir } = context;
+    // 使用 workDir 作为基础路径
+    const files = await glob(params.pattern || '**/*', {
+      cwd: workDir,
+      ignore: ['node_modules/**']
+    });
+    return { success: true, result: files.join('\n') };
+  }
+});
+ +

错误处理

+ +
toolRegistry.register({
+  name: 'read_database',
+  description: '从数据库读取数据',
+  parameters: z.object({
+    query: z.string()
+  }),
+  execute: async (params) => {
+    try {
+      const result = await db.query(params.query);
+      return {
+        success: true,
+        result: JSON.stringify(result, null, 2)
+      };
+    } catch (error) {
+      // 返回错误信息,AI 可以根据错误调整
+      return {
+        success: false,
+        error: `数据库查询失败: ${error.message}`
+      };
+    }
+  }
+});
+ +

异步和流式结果

+ +
toolRegistry.register({
+  name: 'long_running_task',
+  description: '执行长时间运行的任务',
+  parameters: z.object({
+    taskId: z.string()
+  }),
+  execute: async (params, context) => {
+    const { abortSignal } = context;
+
+    for (let i = 0; i < 100; i++) {
+      // 检查是否被取消
+      if (abortSignal?.aborted) {
+        return { success: false, error: '任务已取消' };
+      }
+
+      await processStep(i);
+    }
+
+    return { success: true, result: '任务完成' };
+  }
+});
+ +

权限控制

+ +

可以为工具设置权限级别:

+ +
toolRegistry.register({
+  name: 'delete_file',
+  description: '删除文件',
+  parameters: z.object({
+    path: z.string()
+  }),
+  // 需要用户确认
+  requiresConfirmation: true,
+  // 权限级别
+  permissionLevel: 'dangerous',
+  execute: async (params, context) => {
+    await fs.unlink(path.join(context.workDir, params.path));
+    return { success: true, result: `已删除: ${params.path}` };
+  }
+});
+ +

工具分组

+ +
// 创建工具组
+const databaseTools = createToolGroup('database', {
+  description: '数据库操作工具',
+  tools: [
+    {
+      name: 'query',
+      description: '执行 SQL 查询',
+      parameters: z.object({ sql: z.string() }),
+      execute: async (params) => { /* ... */ }
+    },
+    {
+      name: 'insert',
+      description: '插入数据',
+      parameters: z.object({
+        table: z.string(),
+        data: z.record(z.any())
+      }),
+      execute: async (params) => { /* ... */ }
+    }
+  ]
+});
+
+// 注册工具组
+toolRegistry.registerGroup(databaseTools);
+
+// AI 会看到: database_query, database_insert
+ +

完整示例:GitHub 工具

+ +
import { z } from 'zod';
+import { toolRegistry } from '@ai-assistant/core';
+import { Octokit } from '@octokit/rest';
+
+const octokit = new Octokit({
+  auth: process.env.GITHUB_TOKEN
+});
+
+// 创建 Issue
+toolRegistry.register({
+  name: 'github_create_issue',
+  description: '在 GitHub 仓库中创建 Issue',
+  parameters: z.object({
+    owner: z.string().describe('仓库所有者'),
+    repo: z.string().describe('仓库名称'),
+    title: z.string().describe('Issue 标题'),
+    body: z.string().describe('Issue 内容'),
+    labels: z.array(z.string()).optional().describe('标签列表')
+  }),
+  execute: async (params) => {
+    const { owner, repo, title, body, labels } = params;
+
+    const { data } = await octokit.issues.create({
+      owner,
+      repo,
+      title,
+      body,
+      labels
+    });
+
+    return {
+      success: true,
+      result: `Issue 创建成功: ${data.html_url}`
+    };
+  }
+});
+
+// 列出 PR
+toolRegistry.register({
+  name: 'github_list_prs',
+  description: '列出 GitHub 仓库的 Pull Requests',
+  parameters: z.object({
+    owner: z.string(),
+    repo: z.string(),
+    state: z.enum(['open', 'closed', 'all']).default('open')
+  }),
+  execute: async (params) => {
+    const { owner, repo, state } = params;
+
+    const { data } = await octokit.pulls.list({
+      owner,
+      repo,
+      state
+    });
+
+    const prs = data.map(pr => `#${pr.number}: ${pr.title}`).join('\n');
+
+    return {
+      success: true,
+      result: prs || '没有找到 PR'
+    };
+  }
+});
+ +

测试工具

+ +
import { describe, it, expect } from 'vitest';
+import { toolRegistry } from '@ai-assistant/core';
+
+describe('get_weather tool', () => {
+  it('should return weather for valid city', async () => {
+    const tool = toolRegistry.get('get_weather');
+    const result = await tool.execute(
+      { city: 'Beijing', units: 'celsius' },
+      { workDir: '/tmp', sessionId: 'test' }
+    );
+
+    expect(result.success).toBe(true);
+    expect(result.result).toContain('Beijing');
+  });
+
+  it('should handle invalid city', async () => {
+    const tool = toolRegistry.get('get_weather');
+    const result = await tool.execute(
+      { city: 'InvalidCity123', units: 'celsius' },
+      { workDir: '/tmp', sessionId: 'test' }
+    );
+
+    expect(result.success).toBe(false);
+  });
+});
+ +

最佳实践

+ + + +

相关文档

+ +
+ +

工具系统

+

内置工具详解

+
+ + +

MCP 服务器

+

通过 MCP 协议扩展工具

+
+
+
diff --git a/packages/website/src/pages/docs/extend/hooks.astro b/packages/website/src/pages/docs/extend/hooks.astro new file mode 100644 index 0000000..5f8332f --- /dev/null +++ b/packages/website/src/pages/docs/extend/hooks.astro @@ -0,0 +1,364 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

Hooks 系统

+ +

+ Hooks 允许你在 Agent 执行的关键节点注入自定义逻辑, + 用于日志记录、监控、修改行为等场景。 +

+ +

Hook 类型

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hook触发时机用途
beforeChat发送消息前修改消息、验证输入
afterChat收到响应后日志记录、响应处理
beforeToolCall工具调用前参数验证、权限检查
afterToolCall工具执行后结果处理、审计日志
onError发生错误时错误处理、告警
onStream流式数据块实时处理、进度显示
+ +

注册 Hook

+ +
import { Agent } from '@ai-assistant/core';
+
+const agent = new Agent({
+  apiKey: process.env.ANTHROPIC_API_KEY,
+  hooks: {
+    beforeChat: async (context) => {
+      console.log('即将发送消息:', context.message);
+      // 可以修改消息
+      return {
+        ...context,
+        message: context.message + '\n请用简洁的方式回答。'
+      };
+    },
+
+    afterChat: async (context) => {
+      console.log('收到响应:', context.response);
+      // 记录到数据库
+      await db.logs.insert({
+        sessionId: context.sessionId,
+        message: context.message,
+        response: context.response,
+        timestamp: new Date()
+      });
+    }
+  }
+});
+ +

工具 Hooks

+ +
const agent = new Agent({
+  apiKey: process.env.ANTHROPIC_API_KEY,
+  hooks: {
+    beforeToolCall: async (context) => {
+      const { tool, params } = context;
+
+      // 权限检查
+      if (tool.name === 'execute_bash' && !isAllowedCommand(params.command)) {
+        throw new Error('命令不被允许');
+      }
+
+      // 记录工具调用
+      console.log(`调用工具: ${tool.name}`, params);
+
+      return context;
+    },
+
+    afterToolCall: async (context) => {
+      const { tool, params, result, duration } = context;
+
+      // 审计日志
+      await auditLog.record({
+        tool: tool.name,
+        params,
+        result: result.success ? 'success' : 'failure',
+        duration,
+        timestamp: new Date()
+      });
+
+      // 可以修改结果
+      if (tool.name === 'read_file' && result.success) {
+        // 过滤敏感信息
+        return {
+          ...context,
+          result: {
+            ...result,
+            result: filterSensitiveData(result.result)
+          }
+        };
+      }
+
+      return context;
+    }
+  }
+});
+ +

错误处理 Hook

+ +
const agent = new Agent({
+  apiKey: process.env.ANTHROPIC_API_KEY,
+  hooks: {
+    onError: async (context) => {
+      const { error, phase, tool } = context;
+
+      // 发送告警
+      await alertService.send({
+        level: 'error',
+        message: error.message,
+        context: {
+          phase, // 'chat' | 'tool' | 'stream'
+          tool: tool?.name,
+          sessionId: context.sessionId
+        }
+      });
+
+      // 可以选择恢复或重新抛出
+      if (error.code === 'RATE_LIMIT') {
+        // 等待后重试
+        await sleep(5000);
+        return { retry: true };
+      }
+
+      // 重新抛出错误
+      throw error;
+    }
+  }
+});
+ +

流式处理 Hook

+ +
const agent = new Agent({
+  apiKey: process.env.ANTHROPIC_API_KEY,
+  hooks: {
+    onStream: async (context) => {
+      const { chunk, type, accumulated } = context;
+
+      if (type === 'text') {
+        // 实时显示
+        process.stdout.write(chunk);
+      } else if (type === 'tool_call') {
+        // 显示工具调用进度
+        console.log(`\n[调用工具: ${chunk.name}]`);
+      }
+
+      // 进度回调
+      if (context.onProgress) {
+        context.onProgress({
+          type,
+          content: chunk,
+          total: accumulated.length
+        });
+      }
+    }
+  }
+});
+ +

Hook 链

+ +

可以注册多个同类型的 Hook,按顺序执行:

+ +
import { createHookChain } from '@ai-assistant/core';
+
+const hooks = createHookChain();
+
+// 添加日志 Hook
+hooks.add('beforeChat', async (ctx) => {
+  console.log('[Logger] 消息:', ctx.message);
+  return ctx;
+});
+
+// 添加验证 Hook
+hooks.add('beforeChat', async (ctx) => {
+  if (ctx.message.length > 10000) {
+    throw new Error('消息过长');
+  }
+  return ctx;
+});
+
+// 添加修改 Hook
+hooks.add('beforeChat', async (ctx) => {
+  return {
+    ...ctx,
+    message: ctx.message.trim()
+  };
+});
+
+const agent = new Agent({
+  apiKey: process.env.ANTHROPIC_API_KEY,
+  hooks: hooks.toObject()
+});
+ +

条件 Hook

+ +
import { createConditionalHook } from '@ai-assistant/core';
+
+// 只在特定条件下执行的 Hook
+const debugHook = createConditionalHook(
+  // 条件函数
+  (ctx) => process.env.DEBUG === 'true',
+  // Hook 实现
+  {
+    beforeToolCall: async (ctx) => {
+      console.log('[DEBUG] 工具调用:', ctx.tool.name, ctx.params);
+      return ctx;
+    },
+    afterToolCall: async (ctx) => {
+      console.log('[DEBUG] 工具结果:', ctx.result);
+      return ctx;
+    }
+  }
+);
+
+const agent = new Agent({
+  apiKey: process.env.ANTHROPIC_API_KEY,
+  hooks: debugHook
+});
+ +

内置 Hooks

+ +

日志 Hook

+ +
import { createLoggerHook } from '@ai-assistant/core/hooks';
+
+const loggerHook = createLoggerHook({
+  level: 'info',
+  output: 'file',
+  path: './logs/agent.log',
+  format: 'json'
+});
+
+const agent = new Agent({
+  hooks: loggerHook
+});
+ +

速率限制 Hook

+ +
import { createRateLimitHook } from '@ai-assistant/core/hooks';
+
+const rateLimitHook = createRateLimitHook({
+  maxRequests: 10,
+  windowMs: 60000, // 1 分钟
+  onLimit: async () => {
+    console.log('达到速率限制,等待中...');
+  }
+});
+
+const agent = new Agent({
+  hooks: rateLimitHook
+});
+ +

缓存 Hook

+ +
import { createCacheHook } from '@ai-assistant/core/hooks';
+
+const cacheHook = createCacheHook({
+  ttl: 3600, // 1 小时
+  storage: 'redis',
+  // 只缓存特定工具的结果
+  tools: ['read_file', 'search_code']
+});
+
+const agent = new Agent({
+  hooks: cacheHook
+});
+ +

Hook 上下文类型

+ +
interface BeforeChatContext {
+  message: string | ContentBlock[];
+  sessionId: string;
+  history: Message[];
+}
+
+interface AfterChatContext extends BeforeChatContext {
+  response: string;
+  toolCalls: ToolCall[];
+  usage: TokenUsage;
+}
+
+interface BeforeToolCallContext {
+  tool: Tool;
+  params: Record<string, any>;
+  sessionId: string;
+}
+
+interface AfterToolCallContext extends BeforeToolCallContext {
+  result: ToolResult;
+  duration: number;
+}
+
+interface ErrorContext {
+  error: Error;
+  phase: 'chat' | 'tool' | 'stream';
+  tool?: Tool;
+  sessionId: string;
+}
+
+interface StreamContext {
+  chunk: string | ToolCallChunk;
+  type: 'text' | 'tool_call' | 'tool_result';
+  accumulated: string;
+}
+ +

最佳实践

+ + + +

相关文档

+ +
+ +

Agent 系统

+

了解 Agent 核心架构

+
+ + +

自定义工具

+

创建自定义工具

+
+
+
diff --git a/packages/website/src/pages/docs/extend/mcp-server.astro b/packages/website/src/pages/docs/extend/mcp-server.astro new file mode 100644 index 0000000..37927c9 --- /dev/null +++ b/packages/website/src/pages/docs/extend/mcp-server.astro @@ -0,0 +1,423 @@ +--- +import DocsLayout from '../../../layouts/DocsLayout.astro'; +--- + + +

MCP 服务器开发

+ +

+ Model Context Protocol (MCP) 是一个开放协议,允许你创建服务器来扩展 AI 的能力。 + 通过开发 MCP 服务器,可以让 AI 访问自定义数据源、执行特定操作、使用预定义提示等。 +

+ +

MCP 服务器能力

+ + + +

快速开始

+ +

项目初始化

+ +
# 创建项目目录
+mkdir my-mcp-server && cd my-mcp-server
+
+# 初始化 npm 项目
+npm init -y
+
+# 安装依赖
+npm install @modelcontextprotocol/sdk zod
+
+# 安装开发依赖
+npm install -D typescript @types/node tsx
+ +

TypeScript 配置

+ +
// tsconfig.json
+{
+  "compilerOptions": {
+    "target": "ES2022",
+    "module": "NodeNext",
+    "moduleResolution": "NodeNext",
+    "outDir": "dist",
+    "strict": true,
+    "esModuleInterop": true
+  },
+  "include": ["src"]
+}
+ +

基本服务器结构

+ +
// src/index.ts
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import {
+  CallToolRequestSchema,
+  ListToolsRequestSchema,
+} from '@modelcontextprotocol/sdk/types.js';
+
+// 创建服务器实例
+const server = new Server(
+  {
+    name: 'my-mcp-server',
+    version: '1.0.0',
+  },
+  {
+    capabilities: {
+      tools: {},
+      resources: {},
+      prompts: {},
+    },
+  }
+);
+
+// 列出可用工具
+server.setRequestHandler(ListToolsRequestSchema, async () => ({
+  tools: [
+    {
+      name: 'hello',
+      description: '返回问候语',
+      inputSchema: {
+        type: 'object',
+        properties: {
+          name: {
+            type: 'string',
+            description: '要问候的名字',
+          },
+        },
+        required: ['name'],
+      },
+    },
+  ],
+}));
+
+// 处理工具调用
+server.setRequestHandler(CallToolRequestSchema, async (request) => {
+  if (request.params.name === 'hello') {
+    const name = request.params.arguments?.name as string;
+    return {
+      content: [
+        {
+          type: 'text',
+          text: `你好,${name}!`,
+        },
+      ],
+    };
+  }
+  throw new Error(`未知工具: ${request.params.name}`);
+});
+
+// 启动服务器
+async function main() {
+  const transport = new StdioServerTransport();
+  await server.connect(transport);
+  console.error('MCP 服务器已启动');
+}
+
+main().catch(console.error);
+ +

添加资源

+ +
import {
+  ListResourcesRequestSchema,
+  ReadResourceRequestSchema,
+} from '@modelcontextprotocol/sdk/types.js';
+
+// 列出资源
+server.setRequestHandler(ListResourcesRequestSchema, async () => ({
+  resources: [
+    {
+      uri: 'config://app/settings',
+      name: '应用配置',
+      description: '当前应用配置',
+      mimeType: 'application/json',
+    },
+    {
+      uri: 'db://users/list',
+      name: '用户列表',
+      description: '所有用户数据',
+      mimeType: 'application/json',
+    },
+  ],
+}));
+
+// 读取资源
+server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
+  const { uri } = request.params;
+
+  if (uri === 'config://app/settings') {
+    return {
+      contents: [
+        {
+          uri,
+          mimeType: 'application/json',
+          text: JSON.stringify({
+            theme: 'dark',
+            language: 'zh-CN',
+            version: '1.0.0',
+          }),
+        },
+      ],
+    };
+  }
+
+  if (uri === 'db://users/list') {
+    const users = await db.users.findAll();
+    return {
+      contents: [
+        {
+          uri,
+          mimeType: 'application/json',
+          text: JSON.stringify(users),
+        },
+      ],
+    };
+  }
+
+  throw new Error(`未知资源: ${uri}`);
+});
+ +

添加提示模板

+ +
import {
+  ListPromptsRequestSchema,
+  GetPromptRequestSchema,
+} from '@modelcontextprotocol/sdk/types.js';
+
+// 列出提示
+server.setRequestHandler(ListPromptsRequestSchema, async () => ({
+  prompts: [
+    {
+      name: 'code-review',
+      description: '代码审查提示',
+      arguments: [
+        {
+          name: 'file',
+          description: '要审查的文件路径',
+          required: true,
+        },
+        {
+          name: 'focus',
+          description: '审查重点(安全/性能/可读性)',
+          required: false,
+        },
+      ],
+    },
+  ],
+}));
+
+// 获取提示
+server.setRequestHandler(GetPromptRequestSchema, async (request) => {
+  const { name, arguments: args } = request.params;
+
+  if (name === 'code-review') {
+    const file = args?.file as string;
+    const focus = (args?.focus as string) || '整体质量';
+
+    return {
+      messages: [
+        {
+          role: 'user',
+          content: {
+            type: 'text',
+            text: `请审查文件 ${file},重点关注: ${focus}
+
+请按以下格式提供审查意见:
+1. 总体评价
+2. 优点
+3. 需要改进的地方
+4. 具体建议`,
+          },
+        },
+      ],
+    };
+  }
+
+  throw new Error(`未知提示: ${name}`);
+});
+ +

完整示例:数据库 MCP 服务器

+ +
// src/db-server.ts
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import Database from 'better-sqlite3';
+
+const db = new Database('data.db');
+
+const server = new Server(
+  { name: 'sqlite-server', version: '1.0.0' },
+  { capabilities: { tools: {} } }
+);
+
+// 工具列表
+server.setRequestHandler(ListToolsRequestSchema, async () => ({
+  tools: [
+    {
+      name: 'query',
+      description: '执行 SQL 查询',
+      inputSchema: {
+        type: 'object',
+        properties: {
+          sql: { type: 'string', description: 'SQL 查询语句' },
+        },
+        required: ['sql'],
+      },
+    },
+    {
+      name: 'execute',
+      description: '执行 SQL 命令(INSERT/UPDATE/DELETE)',
+      inputSchema: {
+        type: 'object',
+        properties: {
+          sql: { type: 'string', description: 'SQL 命令' },
+          params: {
+            type: 'array',
+            items: {},
+            description: '参数列表',
+          },
+        },
+        required: ['sql'],
+      },
+    },
+    {
+      name: 'schema',
+      description: '获取数据库表结构',
+      inputSchema: {
+        type: 'object',
+        properties: {
+          table: { type: 'string', description: '表名(可选)' },
+        },
+      },
+    },
+  ],
+}));
+
+// 工具调用
+server.setRequestHandler(CallToolRequestSchema, async (request) => {
+  const { name, arguments: args } = request.params;
+
+  switch (name) {
+    case 'query': {
+      const sql = args?.sql as string;
+      // 安全检查:只允许 SELECT
+      if (!sql.trim().toLowerCase().startsWith('select')) {
+        throw new Error('query 只允许 SELECT 语句');
+      }
+      const rows = db.prepare(sql).all();
+      return {
+        content: [{ type: 'text', text: JSON.stringify(rows, null, 2) }],
+      };
+    }
+
+    case 'execute': {
+      const sql = args?.sql as string;
+      const params = (args?.params as any[]) || [];
+      const result = db.prepare(sql).run(...params);
+      return {
+        content: [
+          {
+            type: 'text',
+            text: `执行成功: 影响 ${result.changes} 行`,
+          },
+        ],
+      };
+    }
+
+    case 'schema': {
+      const table = args?.table as string | undefined;
+      let sql = `SELECT name, sql FROM sqlite_master WHERE type='table'`;
+      if (table) {
+        sql += ` AND name = '${table}'`;
+      }
+      const schemas = db.prepare(sql).all();
+      return {
+        content: [{ type: 'text', text: JSON.stringify(schemas, null, 2) }],
+      };
+    }
+
+    default:
+      throw new Error(`未知工具: ${name}`);
+  }
+});
+
+const transport = new StdioServerTransport();
+server.connect(transport);
+ +

在 AI Assistant 中使用

+ +
// mcp.json
+{
+  "mcpServers": {
+    "my-server": {
+      "command": "node",
+      "args": ["./dist/index.js"],
+      "env": {}
+    },
+    "sqlite": {
+      "command": "node",
+      "args": ["./my-mcp-server/dist/db-server.js"],
+      "env": {
+        "DB_PATH": "/path/to/database.db"
+      }
+    }
+  }
+}
+ +

调试与测试

+ +
# 直接运行测试
+echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js
+
+# 使用 MCP Inspector
+npx @modelcontextprotocol/inspector node dist/index.js
+ +

发布服务器

+ +
// package.json
+{
+  "name": "my-mcp-server",
+  "version": "1.0.0",
+  "bin": {
+    "my-mcp-server": "./dist/index.js"
+  },
+  "files": ["dist"],
+  "scripts": {
+    "build": "tsc",
+    "prepublishOnly": "npm run build"
+  }
+}
+ +
# 发布到 npm
+npm publish
+
+# 用户可以这样使用
+npx my-mcp-server
+ +

最佳实践

+ + + +

相关文档

+ +
+ +

MCP 集成

+

了解 MCP 客户端集成

+
+ + +

MCP 官方文档 ↗

+

Model Context Protocol 规范

+
+
+