docs(website): 重构文档为六部分结构

- 重组侧边栏导航为六个模块:入门指南、核心功能、API参考、部署配置、客户端、扩展开发
- 移动核心功能文档到 core/ 目录 (checkpoint, edit-modes, session)
- 新增部署配置文档 (configuration, local, production)
- 新增客户端文档 (web, desktop, cli)
- 新增扩展开发文档 (custom-tools, hooks, mcp-server)
This commit is contained in:
2025-12-18 00:23:15 +08:00
parent 7f683a8aed
commit 6730ba3228
13 changed files with 2668 additions and 14 deletions
@@ -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' },
],
},
];
@@ -0,0 +1,327 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="CLI 命令" description="AI Terminal Assistant 命令行工具使用指南">
<h1>CLI 命令</h1>
<p>
CLI 提供命令行界面,支持启动服务器和连接到远程服务器进行交互式对话。
</p>
<h2>安装</h2>
<pre><code class="language-bash"># 全局安装
npm install -g @ai-assistant/cli
# 或使用 pnpm
pnpm add -g @ai-assistant/cli
# 验证安装
ai-assistant --version</code></pre>
<h2>命令概览</h2>
<table>
<thead>
<tr>
<th>命令</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>serve</code></td>
<td>启动 HTTP 服务器</td>
<td><code>ai-assistant serve</code></td>
</tr>
<tr>
<td><code>attach</code></td>
<td>连接到服务器</td>
<td><code>ai-assistant attach http://localhost:3000</code></td>
</tr>
<tr>
<td><code>--help</code></td>
<td>显示帮助信息</td>
<td><code>ai-assistant --help</code></td>
</tr>
<tr>
<td><code>--version</code></td>
<td>显示版本号</td>
<td><code>ai-assistant --version</code></td>
</tr>
</tbody>
</table>
<h2>serve 命令</h2>
<p>启动 AI Assistant HTTP 服务器,提供 REST API 和 WebSocket 接口。</p>
<pre><code class="language-bash">ai-assistant serve [选项]</code></pre>
<h3>选项</h3>
<table>
<thead>
<tr>
<th>选项</th>
<th>说明</th>
<th>默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>-p, --port &lt;port&gt;</code></td>
<td>服务器端口</td>
<td>3000</td>
</tr>
<tr>
<td><code>-h, --host &lt;host&gt;</code></td>
<td>监听地址</td>
<td>localhost</td>
</tr>
<tr>
<td><code>-d, --dir &lt;path&gt;</code></td>
<td>工作目录</td>
<td>当前目录</td>
</tr>
<tr>
<td><code>--auth</code></td>
<td>启用认证</td>
<td>非 localhost 时自动启用</td>
</tr>
<tr>
<td><code>--token &lt;token&gt;</code></td>
<td>指定认证 Token</td>
<td>自动生成</td>
</tr>
</tbody>
</table>
<h3>示例</h3>
<pre><code class="language-bash"># 基本启动
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</code></pre>
<h3>输出示例</h3>
<pre><code class="language-text">🚀 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</code></pre>
<h2>attach 命令</h2>
<p>连接到运行中的 AI Assistant 服务器,进行交互式对话。</p>
<pre><code class="language-bash">ai-assistant attach &lt;url&gt; [选项]</code></pre>
<h3>选项</h3>
<table>
<thead>
<tr>
<th>选项</th>
<th>说明</th>
<th>默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>-t, --token &lt;token&gt;</code></td>
<td>认证 Token</td>
<td>-</td>
</tr>
<tr>
<td><code>-s, --session &lt;id&gt;</code></td>
<td>指定会话 ID</td>
<td>自动创建</td>
</tr>
</tbody>
</table>
<h3>示例</h3>
<pre><code class="language-bash"># 连接本地服务器
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</code></pre>
<h3>交互式界面</h3>
<pre><code class="language-text">✓ 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: _</code></pre>
<h2>交互式命令</h2>
<p>在 attach 模式下,支持以下交互式命令:</p>
<table>
<thead>
<tr>
<th>命令</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/exit</code> 或 <code>/quit</code></td>
<td>退出交互</td>
</tr>
<tr>
<td><code>/clear</code></td>
<td>清空当前会话历史</td>
</tr>
<tr>
<td><code>/new</code></td>
<td>创建新会话</td>
</tr>
<tr>
<td><code>/sessions</code></td>
<td>列出所有会话</td>
</tr>
<tr>
<td><code>/switch &lt;id&gt;</code></td>
<td>切换到指定会话</td>
</tr>
<tr>
<td><code>/status</code></td>
<td>显示连接状态</td>
</tr>
<tr>
<td><code>/help</code></td>
<td>显示帮助信息</td>
</tr>
</tbody>
</table>
<h2>环境变量</h2>
<table>
<thead>
<tr>
<th>变量</th>
<th>说明</th>
<th>命令</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>ANTHROPIC_API_KEY</code></td>
<td>Anthropic API Key</td>
<td>serve</td>
</tr>
<tr>
<td><code>AI_ASSISTANT_TOKEN</code></td>
<td>默认认证 Token</td>
<td>attach</td>
</tr>
<tr>
<td><code>AI_ASSISTANT_URL</code></td>
<td>默认服务器地址</td>
<td>attach</td>
</tr>
</tbody>
</table>
<pre><code class="language-bash"># 设置环境变量
export ANTHROPIC_API_KEY=sk-ant-...
export AI_ASSISTANT_TOKEN=my-token
export AI_ASSISTANT_URL=http://localhost:3000
# 使用环境变量(无需每次指定)
ai-assistant attach</code></pre>
<h2>配置文件</h2>
<p>可以在 <code>~/.ai-assistant/config.json</code> 中配置默认选项:</p>
<pre><code class="language-json">{
"defaultServer": "http://localhost:3000",
"defaultToken": "your-token",
"theme": "dark",
"historySize": 1000,
"autoConnect": true
}</code></pre>
<h2>开发模式运行</h2>
<p>在项目开发中直接运行:</p>
<pre><code class="language-bash"># 使用 bun 运行
cd packages/cli
bun run src/index.ts serve --port 3000
# 或使用 tsx
npx tsx src/index.ts attach http://localhost:3000</code></pre>
<h2>退出码</h2>
<table>
<thead>
<tr>
<th>退出码</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr><td>0</td><td>正常退出</td></tr>
<tr><td>1</td><td>一般错误</td></tr>
<tr><td>2</td><td>连接失败</td></tr>
<tr><td>3</td><td>认证失败</td></tr>
</tbody>
</table>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/deploy/local" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">本地部署</h3>
<p class="text-sm text-gray-400">本地开发环境搭建</p>
</a>
<a href="/docs/api/rest" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">REST API</h3>
<p class="text-sm text-gray-400">API 端点文档</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,287 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="桌面应用" description="AI Terminal Assistant 桌面客户端 (Tauri)">
<h1>桌面应用</h1>
<p class="text-yellow-400 font-medium">🚧 开发中 - 基础功能已实现</p>
<p>
桌面应用基于 Tauri 构建,提供原生桌面体验,支持 Windows、macOS 和 Linux。
复用 Web 前端代码,结合 Rust 后端提供更好的性能和系统集成。
</p>
<h2>功能特性</h2>
<ul>
<li><strong>跨平台</strong> - 支持 Windows、macOS、Linux</li>
<li><strong>原生性能</strong> - Rust 后端,低内存占用</li>
<li><strong>系统集成</strong> - 系统托盘、快捷键、通知</li>
<li><strong>离线支持</strong> - 本地数据存储</li>
<li><strong>自动更新</strong> - 内置更新机制</li>
</ul>
<h2>系统要求</h2>
<h3>开发环境</h3>
<ul>
<li>Node.js 18+</li>
<li>Rust 1.70+</li>
<li>pnpm 8+</li>
</ul>
<h3>平台依赖</h3>
<pre><code class="language-bash"># 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</code></pre>
<h2>快速开始</h2>
<h3>开发模式</h3>
<pre><code class="language-bash"># 进入 desktop 包目录
cd packages/desktop
# 安装依赖
pnpm install
# 启动开发模式
pnpm tauri dev</code></pre>
<h3>构建发布版本</h3>
<pre><code class="language-bash"># 构建当前平台
pnpm tauri build
# 输出目录:
# - macOS: src-tauri/target/release/bundle/dmg/
# - Windows: src-tauri/target/release/bundle/msi/
# - Linux: src-tauri/target/release/bundle/deb/</code></pre>
<h2>项目结构</h2>
<pre><code class="language-text">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</code></pre>
<h2>Tauri 配置</h2>
<pre><code class="language-json">// 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"
]
}
}</code></pre>
<h2>Tauri 命令</h2>
<p>在 Rust 中定义可从前端调用的命令:</p>
<pre><code class="language-rust">// src-tauri/src/commands.rs
use tauri::command;
#[command]
pub fn get_system_info() -> Result&lt;SystemInfo, String&gt; {
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&lt;(), String&gt; {
// 打开项目目录
std::env::set_current_dir(&path)
.map_err(|e| e.to_string())
}</code></pre>
<p>在前端调用:</p>
<pre><code class="language-typescript">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' });</code></pre>
<h2>系统托盘</h2>
<pre><code class="language-rust">// src-tauri/src/tray.rs
use tauri::{
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
Manager,
};
pub fn create_tray(app: &tauri::App) -> Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {
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(())
}</code></pre>
<h2>快捷键</h2>
<pre><code class="language-rust">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()
)?;
}</code></pre>
<h2>文件系统访问</h2>
<pre><code class="language-typescript">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');
}</code></pre>
<h2>自动更新</h2>
<pre><code class="language-json">// tauri.conf.json
{
"plugins": {
"updater": {
"active": true,
"endpoints": [
"https://releases.example.com/{{target}}/{{arch}}/{{current_version}}"
],
"pubkey": "YOUR_PUBLIC_KEY"
}
}
}</code></pre>
<pre><code class="language-typescript">import { check } from '@tauri-apps/plugin-updater';
async function checkForUpdates() {
const update = await check();
if (update?.available) {
console.log(`发现新版本: ${update.version}`);
await update.downloadAndInstall();
}
}</code></pre>
<h2>开发注意事项</h2>
<ul>
<li>Tauri 构建较慢,开发时建议使用 <code>pnpm tauri dev</code> 热重载</li>
<li>前端代码变更会自动重载,Rust 代码需要重新编译</li>
<li>跨平台测试建议使用 CI/CD 自动化</li>
<li>敏感信息应使用 Tauri 的安全存储 API</li>
</ul>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/clients/web" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">Web 前端</h3>
<p class="text-sm text-gray-400">React Web 客户端</p>
</a>
<a href="https://tauri.app/v1/guides/" target="_blank" rel="noopener" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">Tauri 官方文档 ↗</h3>
<p class="text-sm text-gray-400">Tauri 框架文档</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,253 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="Web 前端" description="AI Terminal Assistant Web 客户端使用指南">
<h1>Web 前端</h1>
<p>
Web 前端是基于 React + Vite 构建的现代化 Web 应用,提供完整的 AI 对话交互界面。
</p>
<h2>功能特性</h2>
<ul>
<li><strong>实时对话</strong> - WebSocket 流式响应</li>
<li><strong>工具可视化</strong> - 实时显示工具调用和结果</li>
<li><strong>权限管理</strong> - 交互式权限审批</li>
<li><strong>代码高亮</strong> - 语法高亮和 Diff 显示</li>
<li><strong>会话管理</strong> - 多会话切换</li>
<li><strong>响应式设计</strong> - 适配桌面和移动设备</li>
</ul>
<h2>快速开始</h2>
<h3>开发模式</h3>
<pre><code class="language-bash"># 进入 web 包目录
cd packages/web
# 安装依赖
pnpm install
# 启动开发服务器
pnpm dev
# 访问 http://localhost:5173</code></pre>
<h3>生产构建</h3>
<pre><code class="language-bash"># 构建生产版本
pnpm build
# 预览构建结果
pnpm preview
# 输出目录: dist/</code></pre>
<h2>环境配置</h2>
<p>在 <code>.env</code> 或 <code>.env.local</code> 中配置:</p>
<pre><code class="language-bash"># API 服务器地址
VITE_API_URL=http://localhost:3000
# WebSocket 地址(可选,默认从 API_URL 推导)
VITE_WS_URL=ws://localhost:3000
# 认证 Token(远程连接时需要)
VITE_AUTH_TOKEN=your-auth-token</code></pre>
<h2>项目结构</h2>
<pre><code class="language-text">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 配置</code></pre>
<h2>核心组件</h2>
<h3>ChatContainer</h3>
<p>主聊天容器,管理消息列表和输入:</p>
<pre><code class="language-tsx">import { ChatContainer } from '@/components/Chat';
function App() {
return (
&lt;ChatContainer
sessionId="session-123"
onMessage={(msg) => console.log(msg)}
/&gt;
);
}</code></pre>
<h3>MessageList</h3>
<p>消息列表组件,支持多种消息类型:</p>
<pre><code class="language-tsx">import { MessageList } from '@/components/Message';
&lt;MessageList
messages={messages}
onToolApprove={handleToolApprove}
onToolReject={handleToolReject}
/&gt;</code></pre>
<h3>ToolCallDisplay</h3>
<p>工具调用展示组件:</p>
<pre><code class="language-tsx">import { ToolCallDisplay } from '@/components/Tool';
&lt;ToolCallDisplay
tool={{
name: 'read_file',
params: { path: '/src/index.ts' },
status: 'completed',
result: '文件内容...'
}}
/&gt;</code></pre>
<h2>WebSocket 集成</h2>
<pre><code class="language-typescript">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]);
}</code></pre>
<h2>状态管理</h2>
<p>使用 Zustand 进行状态管理:</p>
<pre><code class="language-typescript">import { create } from 'zustand';
interface ChatStore {
messages: Message[];
currentSession: string | null;
addMessage: (msg: Message) => void;
setSession: (id: string) => void;
}
export const useChatStore = create&lt;ChatStore&gt;((set) => ({
messages: [],
currentSession: null,
addMessage: (msg) => set((state) => ({
messages: [...state.messages, msg]
})),
setSession: (id) => set({ currentSession: id })
}));</code></pre>
<h2>主题定制</h2>
<p>使用 Tailwind CSS 自定义主题:</p>
<pre><code class="language-javascript">// tailwind.config.js
export default {
theme: {
extend: {
colors: {
primary: {
50: '#f0f9ff',
// ...
900: '#0c4a6e',
},
background: '#0a0a0a',
surface: '#1a1a1a',
},
fontFamily: {
mono: ['JetBrains Mono', 'monospace'],
},
},
},
};</code></pre>
<h2>部署</h2>
<h3>静态部署</h3>
<pre><code class="language-bash"># 构建
VITE_API_URL=https://api.example.com pnpm build
# 部署 dist/ 目录到任何静态托管服务
# - Vercel
# - Netlify
# - Cloudflare Pages
# - Nginx</code></pre>
<h3>Docker 部署</h3>
<pre><code class="language-dockerfile"># 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</code></pre>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/api/websocket" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">WebSocket API</h3>
<p class="text-sm text-gray-400">实时通信协议</p>
</a>
<a href="/docs/clients/desktop" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">桌面应用</h3>
<p class="text-sm text-gray-400">Tauri 桌面客户端</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,215 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="配置管理" description="AI Terminal Assistant 配置管理指南">
<h1>配置管理</h1>
<p>
AI Terminal Assistant 支持多层配置系统,可以通过环境变量、配置文件等方式进行配置。
</p>
<h2>环境变量</h2>
<h3>必需配置</h3>
<table>
<thead>
<tr>
<th>变量名</th>
<th>说明</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>ANTHROPIC_API_KEY</code></td>
<td>Anthropic API 密钥</td>
<td><code>sk-ant-...</code></td>
</tr>
</tbody>
</table>
<h3>可选配置</h3>
<table>
<thead>
<tr>
<th>变量名</th>
<th>说明</th>
<th>默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>OPENAI_API_KEY</code></td>
<td>OpenAI API 密钥</td>
<td>-</td>
</tr>
<tr>
<td><code>DEEPSEEK_API_KEY</code></td>
<td>DeepSeek API 密钥</td>
<td>-</td>
</tr>
<tr>
<td><code>TAVILY_API_KEY</code></td>
<td>Tavily 搜索 API 密钥</td>
<td>-</td>
</tr>
<tr>
<td><code>AI_MODEL</code></td>
<td>默认模型</td>
<td><code>claude-sonnet-4-20250514</code></td>
</tr>
<tr>
<td><code>AI_MAX_TOKENS</code></td>
<td>最大输出 tokens</td>
<td><code>4096</code></td>
</tr>
<tr>
<td><code>AI_TEMPERATURE</code></td>
<td>温度参数</td>
<td><code>0.7</code></td>
</tr>
</tbody>
</table>
<h2>配置文件</h2>
<h3>.env 文件</h3>
<pre><code class="language-bash"># .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</code></pre>
<h3>项目配置文件</h3>
<p>在项目根目录创建 <code>.ai-assistant/config.json</code></p>
<pre><code class="language-json">&#123;
"model": "claude-sonnet-4-20250514",
"maxTokens": 4096,
"temperature": 0.7,
"systemPrompt": "你是一个专业的编程助手",
"tools": &#123;
"enabled": ["read_file", "write_file", "bash", "grep"],
"disabled": ["web_search"]
&#125;,
"permissions": &#123;
"allowedPaths": ["/project"],
"deniedPaths": ["/project/secrets"],
"autoApprove": ["read_file", "grep"]
&#125;
&#125;</code></pre>
<h2>MCP 服务器配置</h2>
<p>在项目根目录创建 <code>mcp.json</code></p>
<pre><code class="language-json">&#123;
"mcpServers": &#123;
"filesystem": &#123;
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
"env": &#123;&#125;
&#125;,
"github": &#123;
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": &#123;
"GITHUB_TOKEN": "$&#123;GITHUB_TOKEN&#125;"
&#125;
&#125;
&#125;
&#125;</code></pre>
<h2>配置优先级</h2>
<p>配置按以下优先级加载(高 → 低):</p>
<ol>
<li>命令行参数</li>
<li>环境变量</li>
<li>项目配置文件 (<code>.ai-assistant/config.json</code>)</li>
<li>用户配置文件 (<code>~/.config/ai-assistant/config.json</code>)</li>
<li>默认值</li>
</ol>
<h2>服务器配置</h2>
<table>
<thead>
<tr>
<th>参数</th>
<th>环境变量</th>
<th>说明</th>
<th>默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--port</code></td>
<td><code>PORT</code></td>
<td>服务器端口</td>
<td><code>3000</code></td>
</tr>
<tr>
<td><code>--host</code></td>
<td><code>HOST</code></td>
<td>绑定地址</td>
<td><code>127.0.0.1</code></td>
</tr>
<tr>
<td><code>--auth</code></td>
<td><code>AUTH_ENABLED</code></td>
<td>启用认证</td>
<td>远程模式自动启用</td>
</tr>
<tr>
<td><code>--token</code></td>
<td><code>AUTH_TOKEN</code></td>
<td>认证 Token</td>
<td>自动生成</td>
</tr>
</tbody>
</table>
<h2>权限配置</h2>
<pre><code class="language-typescript">interface PermissionConfig &#123;
// 允许访问的路径
allowedPaths: string[];
// 禁止访问的路径
deniedPaths: string[];
// 自动批准的工具
autoApprove: string[];
// 禁用的工具
disabledTools: string[];
// 允许执行的 Shell 命令模式
shellPatterns: string[];
&#125;</code></pre>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/deploy/local" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">本地部署</h3>
<p class="text-sm text-gray-400">开发环境搭建指南</p>
</a>
<a href="/docs/deploy/production" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">生产部署</h3>
<p class="text-sm text-gray-400">服务器和容器部署</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,208 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="本地部署" description="AI Terminal Assistant 本地开发环境搭建">
<h1>本地部署</h1>
<p>
本指南介绍如何在本地搭建 AI Terminal Assistant 开发环境。
</p>
<h2>系统要求</h2>
<ul>
<li><strong>Node.js</strong> 18.0 或更高版本</li>
<li><strong>Bun</strong> 1.0 或更高版本(推荐)</li>
<li><strong>pnpm</strong> 8.0 或更高版本</li>
<li><strong>Git</strong> 2.0 或更高版本</li>
</ul>
<h3>可选依赖</h3>
<ul>
<li><strong>Rust</strong> - 构建桌面应用需要</li>
<li><strong>Python 3</strong> - 部分 MCP 服务器需要</li>
</ul>
<h2>安装步骤</h2>
<h3>1. 克隆仓库</h3>
<pre><code class="language-bash">git clone https://github.com/your-username/ai-terminal-assistant.git
cd ai-terminal-assistant</code></pre>
<h3>2. 安装依赖</h3>
<pre><code class="language-bash"># 使用 pnpm 安装所有依赖
pnpm install</code></pre>
<h3>3. 配置环境变量</h3>
<pre><code class="language-bash"># 复制环境变量模板
cp .env.example .env
# 编辑 .env 文件,添加 API 密钥
# ANTHROPIC_API_KEY=your-api-key</code></pre>
<h3>4. 构建项目</h3>
<pre><code class="language-bash"># 构建核心包
pnpm --filter @ai-assistant/core build
# 构建服务器
pnpm --filter @ai-assistant/server build
# 或一次性构建所有包
pnpm build</code></pre>
<h2>启动开发服务器</h2>
<h3>方式一:分开启动</h3>
<pre><code class="language-bash"># 终端 1:启动 HTTP 服务器
pnpm server:dev
# 终端 2:启动 Web 前端
cd packages/web && pnpm dev</code></pre>
<p>然后访问 <code>http://localhost:5173</code>。</p>
<h3>方式二:使用 CLI</h3>
<pre><code class="language-bash"># 启动服务器
cd packages/cli
bun run src/index.ts serve --port 3000</code></pre>
<h2>开发命令</h2>
<table>
<thead>
<tr>
<th>命令</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pnpm build</code></td>
<td>构建所有包</td>
</tr>
<tr>
<td><code>pnpm test</code></td>
<td>运行所有测试</td>
</tr>
<tr>
<td><code>pnpm --filter @ai-assistant/core build</code></td>
<td>只构建 core 包</td>
</tr>
<tr>
<td><code>pnpm --filter @ai-assistant/core test:watch</code></td>
<td>监视模式运行 core 测试</td>
</tr>
<tr>
<td><code>pnpm server:dev</code></td>
<td>开发模式启动服务器</td>
</tr>
</tbody>
</table>
<h2>项目结构</h2>
<pre><code class="language-text">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</code></pre>
<h2>调试技巧</h2>
<h3>查看 Agent 日志</h3>
<pre><code class="language-bash"># 启用详细日志
DEBUG=ai-assistant:* pnpm server:dev</code></pre>
<h3>测试单个工具</h3>
<pre><code class="language-typescript">import &#123; toolRegistry &#125; from '@ai-assistant/core/tools';
// 获取工具
const readFile = toolRegistry.get('read_file');
// 执行测试
const result = await readFile.execute(&#123;
path: '/path/to/file.ts'
&#125;);
console.log(result);</code></pre>
<h3>VS Code 调试配置</h3>
<pre><code class="language-json">// .vscode/launch.json
&#123;
"version": "0.2.0",
"configurations": [
&#123;
"name": "Debug Server",
"type": "node",
"request": "launch",
"runtimeExecutable": "bun",
"runtimeArgs": ["run"],
"program": "$&#123;workspaceFolder&#125;/packages/server/src/bin/server.ts",
"cwd": "$&#123;workspaceFolder&#125;"
&#125;
]
&#125;</code></pre>
<h2>常见问题</h2>
<h3>依赖安装失败</h3>
<pre><code class="language-bash"># 清理缓存重新安装
rm -rf node_modules pnpm-lock.yaml
pnpm store prune
pnpm install</code></pre>
<h3>端口被占用</h3>
<pre><code class="language-bash"># 查找占用端口的进程
lsof -i :3000
# 使用其他端口
pnpm server:dev -- --port 3001</code></pre>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/deploy/configuration" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">配置管理</h3>
<p class="text-sm text-gray-400">环境变量和配置文件</p>
</a>
<a href="/docs/deploy/production" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">生产部署</h3>
<p class="text-sm text-gray-400">Docker 和服务器部署</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,271 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="生产部署" description="AI Terminal Assistant 生产环境部署指南">
<h1>生产部署</h1>
<p>
本指南介绍如何将 AI Terminal Assistant 部署到生产环境。
</p>
<h2>部署方式</h2>
<ul>
<li><strong>Docker</strong> - 容器化部署(推荐)</li>
<li><strong>直接部署</strong> - 服务器直接运行</li>
<li><strong>Vercel/Cloudflare</strong> - Web 前端静态部署</li>
</ul>
<h2>Docker 部署</h2>
<h3>Dockerfile</h3>
<pre><code class="language-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"]</code></pre>
<h3>Docker Compose</h3>
<pre><code class="language-yaml"># docker-compose.yml
version: '3.8'
services:
ai-assistant:
build: .
ports:
- "3000:3000"
environment:
- ANTHROPIC_API_KEY=$&#123;ANTHROPIC_API_KEY&#125;
- HOST=0.0.0.0
- PORT=3000
- AUTH_ENABLED=true
- AUTH_TOKEN=$&#123;AUTH_TOKEN&#125;
volumes:
- ./projects:/projects:rw
restart: unless-stopped
web:
build:
context: .
dockerfile: Dockerfile.web
ports:
- "80:80"
depends_on:
- ai-assistant
restart: unless-stopped</code></pre>
<h3>运行容器</h3>
<pre><code class="language-bash"># 构建镜像
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</code></pre>
<h2>直接部署</h2>
<h3>系统服务 (systemd)</h3>
<pre><code class="language-ini"># /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</code></pre>
<pre><code class="language-bash"># 启用并启动服务
sudo systemctl enable ai-assistant
sudo systemctl start ai-assistant
# 查看状态
sudo systemctl status ai-assistant
# 查看日志
sudo journalctl -u ai-assistant -f</code></pre>
<h3>PM2 部署</h3>
<pre><code class="language-javascript">// ecosystem.config.js
module.exports = &#123;
apps: [&#123;
name: 'ai-assistant',
script: 'dist/bin/server.js',
interpreter: 'bun',
cwd: '/opt/ai-assistant',
env: &#123;
NODE_ENV: 'production',
PORT: 3000,
HOST: '0.0.0.0'
&#125;,
env_file: '.env',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G'
&#125;]
&#125;;</code></pre>
<pre><code class="language-bash"># 启动
pm2 start ecosystem.config.js
# 保存并开机启动
pm2 save
pm2 startup</code></pre>
<h2>Nginx 反向代理</h2>
<pre><code class="language-nginx"># /etc/nginx/sites-available/ai-assistant
server &#123;
listen 80;
server_name your-domain.com;
# 重定向到 HTTPS
return 301 https://$server_name$request_uri;
&#125;
server &#123;
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/ &#123;
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;
&#125;
# 静态文件
location / &#123;
root /var/www/ai-assistant;
try_files $uri $uri/ /index.html;
&#125;
&#125;</code></pre>
<h2>Web 前端静态部署</h2>
<h3>构建静态文件</h3>
<pre><code class="language-bash"># 设置 API 地址
echo "VITE_API_URL=https://api.your-domain.com" > packages/web/.env.production
# 构建
cd packages/web && pnpm build
# 输出在 dist/ 目录</code></pre>
<h3>Vercel 部署</h3>
<pre><code class="language-json">// vercel.json
&#123;
"buildCommand": "cd packages/web && pnpm build",
"outputDirectory": "packages/web/dist",
"framework": "vite",
"rewrites": [
&#123; "source": "/(.*)", "destination": "/index.html" &#125;
]
&#125;</code></pre>
<h2>安全配置</h2>
<h3>HTTPS 证书</h3>
<pre><code class="language-bash"># 使用 Let's Encrypt
sudo certbot --nginx -d your-domain.com</code></pre>
<h3>防火墙</h3>
<pre><code class="language-bash"># UFW
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable</code></pre>
<h3>认证配置</h3>
<pre><code class="language-bash"># 生成强 Token
openssl rand -hex 32
# 设置环境变量
export AUTH_TOKEN=your-generated-token</code></pre>
<h2>监控与日志</h2>
<pre><code class="language-bash"># 健康检查
curl https://your-domain.com/health
# 查看容器日志
docker logs -f ai-assistant
# 查看系统服务日志
journalctl -u ai-assistant -f</code></pre>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/deploy/configuration" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">配置管理</h3>
<p class="text-sm text-gray-400">环境变量和配置文件</p>
</a>
<a href="/docs/api/rest" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">REST API</h3>
<p class="text-sm text-gray-400">API 端点文档</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,300 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="自定义工具" description="为 AI Terminal Assistant 开发自定义工具">
<h1>自定义工具</h1>
<p>
工具是 AI Agent 与外部世界交互的方式。你可以创建自定义工具来扩展 AI 的能力,
例如访问数据库、调用 API、执行特定业务逻辑等。
</p>
<h2>工具结构</h2>
<p>每个工具需要定义以下属性:</p>
<pre><code class="language-typescript">interface Tool {
name: string; // 工具名称(唯一标识)
description: string; // 工具描述(AI 用于判断何时使用)
parameters: ZodSchema; // 参数 SchemaZod 定义)
execute: (params: T, context: ToolContext) => Promise&lt;ToolResult&gt;;
}</code></pre>
<h2>基本示例</h2>
<pre><code class="language-typescript">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'}`
};
}
});</code></pre>
<h2>工具上下文</h2>
<p><code>ToolContext</code> 提供执行环境信息:</p>
<pre><code class="language-typescript">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') };
}
});</code></pre>
<h2>错误处理</h2>
<pre><code class="language-typescript">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}`
};
}
}
});</code></pre>
<h2>异步和流式结果</h2>
<pre><code class="language-typescript">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: '任务完成' };
}
});</code></pre>
<h2>权限控制</h2>
<p>可以为工具设置权限级别:</p>
<pre><code class="language-typescript">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}` };
}
});</code></pre>
<h2>工具分组</h2>
<pre><code class="language-typescript">// 创建工具组
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</code></pre>
<h2>完整示例:GitHub 工具</h2>
<pre><code class="language-typescript">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'
};
}
});</code></pre>
<h2>测试工具</h2>
<pre><code class="language-typescript">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);
});
});</code></pre>
<h2>最佳实践</h2>
<ul>
<li><strong>描述清晰</strong> - AI 根据描述判断何时使用工具</li>
<li><strong>参数验证</strong> - 使用 Zod 进行严格的参数验证</li>
<li><strong>错误处理</strong> - 返回有意义的错误信息</li>
<li><strong>幂等性</strong> - 尽可能让工具可重复执行</li>
<li><strong>权限控制</strong> - 危险操作需要确认</li>
<li><strong>超时处理</strong> - 长时间操作支持取消</li>
</ul>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/core/tools" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">工具系统</h3>
<p class="text-sm text-gray-400">内置工具详解</p>
</a>
<a href="/docs/extend/mcp-server" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">MCP 服务器</h3>
<p class="text-sm text-gray-400">通过 MCP 协议扩展工具</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,364 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="Hooks 系统" description="AI Terminal Assistant Hooks 扩展机制">
<h1>Hooks 系统</h1>
<p>
Hooks 允许你在 Agent 执行的关键节点注入自定义逻辑,
用于日志记录、监控、修改行为等场景。
</p>
<h2>Hook 类型</h2>
<table>
<thead>
<tr>
<th>Hook</th>
<th>触发时机</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>beforeChat</code></td>
<td>发送消息前</td>
<td>修改消息、验证输入</td>
</tr>
<tr>
<td><code>afterChat</code></td>
<td>收到响应后</td>
<td>日志记录、响应处理</td>
</tr>
<tr>
<td><code>beforeToolCall</code></td>
<td>工具调用前</td>
<td>参数验证、权限检查</td>
</tr>
<tr>
<td><code>afterToolCall</code></td>
<td>工具执行后</td>
<td>结果处理、审计日志</td>
</tr>
<tr>
<td><code>onError</code></td>
<td>发生错误时</td>
<td>错误处理、告警</td>
</tr>
<tr>
<td><code>onStream</code></td>
<td>流式数据块</td>
<td>实时处理、进度显示</td>
</tr>
</tbody>
</table>
<h2>注册 Hook</h2>
<pre><code class="language-typescript">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()
});
}
}
});</code></pre>
<h2>工具 Hooks</h2>
<pre><code class="language-typescript">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;
}
}
});</code></pre>
<h2>错误处理 Hook</h2>
<pre><code class="language-typescript">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;
}
}
});</code></pre>
<h2>流式处理 Hook</h2>
<pre><code class="language-typescript">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
});
}
}
}
});</code></pre>
<h2>Hook 链</h2>
<p>可以注册多个同类型的 Hook,按顺序执行:</p>
<pre><code class="language-typescript">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()
});</code></pre>
<h2>条件 Hook</h2>
<pre><code class="language-typescript">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
});</code></pre>
<h2>内置 Hooks</h2>
<h3>日志 Hook</h3>
<pre><code class="language-typescript">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
});</code></pre>
<h3>速率限制 Hook</h3>
<pre><code class="language-typescript">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
});</code></pre>
<h3>缓存 Hook</h3>
<pre><code class="language-typescript">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
});</code></pre>
<h2>Hook 上下文类型</h2>
<pre><code class="language-typescript">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&lt;string, any&gt;;
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;
}</code></pre>
<h2>最佳实践</h2>
<ul>
<li><strong>保持轻量</strong> - Hook 应该快速执行,避免阻塞</li>
<li><strong>错误处理</strong> - Hook 内的错误应该被妥善处理</li>
<li><strong>不可变性</strong> - 返回新对象而非修改原对象</li>
<li><strong>类型安全</strong> - 使用 TypeScript 确保类型正确</li>
<li><strong>单一职责</strong> - 每个 Hook 只做一件事</li>
</ul>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/core/agent" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">Agent 系统</h3>
<p class="text-sm text-gray-400">了解 Agent 核心架构</p>
</a>
<a href="/docs/extend/custom-tools" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">自定义工具</h3>
<p class="text-sm text-gray-400">创建自定义工具</p>
</a>
</div>
</DocsLayout>
@@ -0,0 +1,423 @@
---
import DocsLayout from '../../../layouts/DocsLayout.astro';
---
<DocsLayout title="MCP 服务器开发" description="开发自定义 Model Context Protocol 服务器">
<h1>MCP 服务器开发</h1>
<p>
Model Context Protocol (MCP) 是一个开放协议,允许你创建服务器来扩展 AI 的能力。
通过开发 MCP 服务器,可以让 AI 访问自定义数据源、执行特定操作、使用预定义提示等。
</p>
<h2>MCP 服务器能力</h2>
<ul>
<li><strong>Tools (工具)</strong> - 可供 AI 调用的函数</li>
<li><strong>Resources (资源)</strong> - 可读取的数据源</li>
<li><strong>Prompts (提示)</strong> - 预定义的提示模板</li>
</ul>
<h2>快速开始</h2>
<h3>项目初始化</h3>
<pre><code class="language-bash"># 创建项目目录
mkdir my-mcp-server && cd my-mcp-server
# 初始化 npm 项目
npm init -y
# 安装依赖
npm install @modelcontextprotocol/sdk zod
# 安装开发依赖
npm install -D typescript @types/node tsx</code></pre>
<h3>TypeScript 配置</h3>
<pre><code class="language-json">// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}</code></pre>
<h2>基本服务器结构</h2>
<pre><code class="language-typescript">// 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);</code></pre>
<h2>添加资源</h2>
<pre><code class="language-typescript">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}`);
});</code></pre>
<h2>添加提示模板</h2>
<pre><code class="language-typescript">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}`);
});</code></pre>
<h2>完整示例:数据库 MCP 服务器</h2>
<pre><code class="language-typescript">// 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);</code></pre>
<h2>在 AI Assistant 中使用</h2>
<pre><code class="language-json">// 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"
}
}
}
}</code></pre>
<h2>调试与测试</h2>
<pre><code class="language-bash"># 直接运行测试
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js
# 使用 MCP Inspector
npx @modelcontextprotocol/inspector node dist/index.js</code></pre>
<h2>发布服务器</h2>
<pre><code class="language-json">// 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"
}
}</code></pre>
<pre><code class="language-bash"># 发布到 npm
npm publish
# 用户可以这样使用
npx my-mcp-server</code></pre>
<h2>最佳实践</h2>
<ul>
<li><strong>输入验证</strong> - 始终验证用户输入</li>
<li><strong>错误处理</strong> - 返回有意义的错误信息</li>
<li><strong>安全性</strong> - 防止 SQL 注入等攻击</li>
<li><strong>文档</strong> - 为工具和资源提供清晰描述</li>
<li><strong>版本管理</strong> - 遵循语义化版本</li>
</ul>
<h2>相关文档</h2>
<div class="grid gap-4 md:grid-cols-2 not-prose mt-6">
<a href="/docs/core/mcp" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">MCP 集成</h3>
<p class="text-sm text-gray-400">了解 MCP 客户端集成</p>
</a>
<a href="https://modelcontextprotocol.io" target="_blank" rel="noopener" class="block rounded-xl border border-gray-800 bg-gray-900/50 p-6 transition hover:border-gray-700 hover:bg-gray-900">
<h3 class="mb-2 text-lg font-semibold text-white">MCP 官方文档 ↗</h3>
<p class="text-sm text-gray-400">Model Context Protocol 规范</p>
</a>
</div>
</DocsLayout>