18 KiB
| date | status | depth | origin |
|---|---|---|---|
| 2026-06-13 | active | standard | null |
feat: Tauri 2.x Desktop Client
Summary
创建 Tauri 2.x 桌面客户端外壳,将现有 Vue 3 GUI 包装为跨平台桌面应用(Windows/macOS/Linux)。Tauri 管理窗口和 Python 后端进程生命周期,前端代码仅做最小适配(动态 API baseURL + Splash 启动流程),不修改任何 GUI 组件、布局、样式或业务逻辑。
Problem Frame
当前 AgentKit GUI 只能通过浏览器访问(agentkit gui 启动后自动打开浏览器),用户需要:
- 手动启动后端进程
- 在浏览器中操作,缺乏原生体验(无系统托盘、无桌面集成、无自动更新)
- 无法像桌面应用一样安装、启动、关闭
竞品(Cursor、Devin)均提供原生桌面客户端。AgentKit 需要对齐这一体验标准。
Key Technical Decisions
KTD-1: Tauri 2.x 作为桌面壳。 Tauri 使用系统 WebView(不打包 Chromium),安装包 ~5-10MB + PyInstaller 产物 ~30-80MB,总计远小于 Electron 方案(~200MB+)。启动快(窗口 <500ms),内存低(~110-200MB vs Electron ~300-500MB)。Tauri 2.x 插件化架构更灵活,capabilities 权限模型更安全,且是长期维护版本。
KTD-2: PyInstaller 打包 Python 后端为 sidecar。 PyInstaller 将 Python 后端打包为独立单文件二进制,Tauri 通过 tauri-plugin-shell sidecar API 管理其生命周期。比 Nuitka 兼容性更好,社区更成熟。
KTD-3: 端口 0 + stdout 解析实现端口发现。 Python 后端以 --port 0 启动,OS 分配随机可用端口,uvicorn 启动后通过 stdout 输出 AGENTKIT_PORT=XXXXX,Rust 侧解析后通过 Tauri IPC 传递给前端。避免端口冲突,无需用户配置。
KTD-4: 前端最小适配策略。 仅修改 api/base.ts(动态 baseURL)和 App.vue(Splash 启动流程),新增 api/tauri.ts(Tauri invoke 封装)和 TitleBar.vue(自定义标题栏)。所有现有 GUI 组件、布局、样式、业务逻辑不做任何修改。
KTD-5: 双窗口 Splash 方案。 Tauri 配置两个窗口:splash(小窗口,加载动画)和 main(主窗口,初始隐藏)。后端就绪后 Rust 侧关闭 splash、显示 main。比前端内 Splash 更干净,不侵入现有 App.vue 的布局逻辑。
High-Level Technical Design
┌──────────────────────────────────────────────────────┐
│ Tauri Application (Rust) │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Splash │ │ Main Window │ │ System Tray │ │
│ │ (loading) │ │ (Vue 3 SPA) │ │ (minimize) │ │
│ └─────────────┘ └──────┬───────┘ └─────────────┘ │
│ │ HTTP/WS │
│ ┌───────────────────────▼──────────────────────────┐│
│ │ Python Backend (sidecar process) ││
│ │ FastAPI + uvicorn on random port ││
│ └──────────────────────────────────────────────────┘│
│ │
│ Rust Modules: │
│ - sidecar.rs: start/stop/health Python process │
│ - tray.rs: system tray menu │
│ - lib.rs: Tauri Builder + plugin registration │
└──────────────────────────────────────────────────────┘
启动序列:
1. 用户双击桌面图标 → Tauri 启动
2. Rust setup() → 创建系统托盘
3. Splash 窗口显示(加载动画)
4. 前端 invoke('start_backend')
5. Rust spawn sidecar: agentkit-server --port 0
6. Python 绑定随机端口 → stdout: AGENTKIT_PORT=XXXXX
7. Rust 解析端口 → 存入 BackendState → emit('backend-ready')
8. 前端设置 apiBaseURL → 健康检查通过
9. Rust 关闭 splash → 显示 main 窗口
关闭序列:
1. 用户点击关闭按钮 → 窗口隐藏到托盘(不退出)
2. 托盘菜单"退出" → Rust 发送 SIGTERM 给 Python 进程
3. Python 优雅关闭 → Tauri app.exit(0)
Scope Boundaries
在范围内:
- Tauri 2.x 项目脚手架和配置
- Rust 侧 sidecar 进程管理(启动/停止/健康检查/端口发现)
- 前端最小适配(api/base.ts 动态 baseURL、api/tauri.ts 封装、App.vue Splash 流程、TitleBar.vue)
- 系统托盘(显示/隐藏窗口、退出)
- 单实例锁
- 自定义标题栏(无边框窗口)
- PyInstaller 打包脚本
- 跨平台 CI 构建(GitHub Actions)
延迟到后续迭代:
- 自动更新器(tauri-plugin-updater 集成 + 签名密钥 + 发布服务器)
- 应用签名和公证(macOS code signing / Windows Authenticode)
- 多语言支持
- 离线模式
- 深度链接(deep link / URL scheme 注册)
- 文件关联
不在范围内:
- 修改现有 GUI 组件、布局、样式
- 修改后端 API 或业务逻辑
- 移动端适配(Tauri 2.x 支持 iOS/Android,但不在本次范围)
- 多用户协作
Implementation Units
U1. Tauri 2.x 项目脚手架
Goal: 创建 Tauri 2.x 项目结构,配置构建管线,验证 dev 模式可运行。
Requirements: KTD-1, KTD-4
Dependencies: 无
Files:
src-tauri/Cargo.toml— Rust 依赖(tauri 2, tauri-plugin-shell, tauri-plugin-single-instance, serde, tokio, reqwest)src-tauri/tauri.conf.json— Tauri 核心配置(窗口、sidecar 声明、bundle 设置)src-tauri/capabilities/default.json— 权限声明src-tauri/src/main.rs— Rust 入口src-tauri/src/lib.rs— Tauri Builder(占位,后续单元填充)src-tauri/build.rs— 构建脚本src-tauri/icons/— 应用图标(占位)package.json— 添加 Tauri CLI 和 API 依赖
Approach:
- 在项目根目录初始化 Tauri 2.x:
npm create tauri-app@latest或手动创建src-tauri/目录 tauri.conf.json配置双窗口(splash + main),main 初始visible: falsebuild.beforeDevCommand指向前端 dev 脚本,build.beforeBuildCommand指向前端 build 脚本build.frontendDist指向前端构建输出目录bundle.externalBin声明 sidecar 二进制名- 安装前端依赖:
@tauri-apps/api@^2,@tauri-apps/plugin-shell@^2 - 验证
npm run tauri dev能启动窗口
Patterns to follow: Tauri 2.x 官方项目结构
Test scenarios:
npm run tauri dev启动后显示 Tauri 窗口(前端内容可能为空,因为后端未启动)npm run tauri build能生成安装包(可能因缺少 sidecar 二进制而失败,此为预期)
Verification: npm run tauri dev 能启动 Tauri 窗口并加载前端页面
U2. Rust Sidecar 进程管理
Goal: 实现 Python 后端进程的启动、停止、健康检查和端口发现。
Requirements: KTD-2, KTD-3
Dependencies: U1
Files:
src-tauri/src/sidecar.rs— sidecar 管理模块(新建)src-tauri/src/lib.rs— 注册 invoke handler 和 BackendStatesrc-tauri/Cargo.toml— 添加regex依赖
Approach:
- 定义
BackendState结构体:port: Mutex<Option<u16>>,pid: Mutex<Option<u32>> - 实现
start_backend命令:- 通过
app.shell().sidecar("agentkit-server")创建 sidecar 命令 - 传入
--port 0和AGENTKIT_GUI_MODE=1环境变量 - spawn 后监听 stdout/stderr,用正则解析
AGENTKIT_PORT=(\d+) - 端口就绪后 emit
backend-ready事件 - 带超时等待(30s)
- 通过
- 实现
get_backend_port命令:返回当前端口 - 实现
stop_backend命令:发送 SIGTERM(Unix)或 taskkill(Windows) - 实现
check_backend_health命令:HTTP GEThttp://127.0.0.1:{port}/api/v1/health - 在
lib.rs中注册所有命令和BackendStatemanaged state
Technical design:
start_backend() flow:
sidecar("agentkit-server").args(["--port", "0"]).env("AGENTKIT_GUI_MODE", "1")
→ spawn → tokio::spawn listen stdout/stderr
→ parse AGENTKIT_PORT=XXXXX → store in BackendState.port
→ emit("backend-ready", { port }) → return port
stop_backend() flow:
BackendState.pid → SIGTERM/taskkill → clear port & pid
Patterns to follow: tauri-plugin-shell sidecar API 文档
Test scenarios:
- 启动 sidecar 后
get_backend_port返回有效端口号 check_backend_health在后端就绪后返回 truestop_backend能成功终止 Python 进程- 后端启动超时(30s)时返回错误
- 后端意外崩溃时 Rust 侧能检测到并清理状态
Verification: 手动测试 invoke('start_backend') → invoke('get_backend_port') → invoke('check_backend_health') → invoke('stop_backend') 全流程
U3. 前端适配 — 动态 API baseURL + Splash 启动流程
Goal: 前端支持 Tauri 环境,动态设置 API baseURL,添加 Splash 启动流程。
Requirements: KTD-3, KTD-4, KTD-5
Dependencies: U2
Files:
src/agentkit/server/frontend/src/api/base.ts— 修改:支持 Tauri 环境动态 baseURLsrc/agentkit/server/frontend/src/api/tauri.ts— 新增:Tauri invoke 封装src/agentkit/server/frontend/src/App.vue— 修改:添加 Splash 启动流程src/agentkit/server/frontend/src/components/layout/SplashScreen.vue— 新增:Splash 加载组件src/agentkit/server/frontend/src/components/layout/TitleBar.vue— 新增:自定义标题栏src/agentkit/server/frontend/src/views/AgentLayout.vue— 修改:集成 TitleBarsrc/agentkit/server/frontend/vite.config.ts— 修改:Tauri 环境适配
Approach:
-
api/tauri.ts:封装 Tauri invoke 调用isTauri()检测是否在 Tauri 环境中('__TAURI_INTERNALS__' in window)startBackend()→invoke('start_backend')getBackendPort()→invoke('get_backend_port')stopBackend()→invoke('stop_backend')checkBackendHealth()→invoke('check_backend_health')
-
api/base.ts:动态 baseURL- 新增
initApiBaseURL()函数 - Tauri 环境:从
getBackendPort()获取端口,设置apiBaseURL = http://127.0.0.1:{port} - 浏览器环境:
apiBaseURL = ''(保持现有相对路径行为) BaseApiClient的request()和createWebSocket()方法使用动态 baseURL
- 新增
-
App.vue:Splash 启动流程- 新增
loading和loadingProgress响应式状态 onMounted时:如果isTauri(),调用startBackend()→initApiBaseURL()→checkBackendHealth()- 加载完成前显示
SplashScreen,完成后显示RouterView - 浏览器环境保持现有行为不变
- 新增
-
SplashScreen.vue:加载动画组件- 品牌 Logo + 加载进度条 + 状态文字("正在启动后端..."、"正在连接...")
- 使用现有 Design Token 变量
-
TitleBar.vue:自定义标题栏data-tauri-drag-region使标题栏可拖拽- 最小化/最大化/关闭按钮(关闭时隐藏到托盘)
- 仅在 Tauri 环境中显示
-
vite.config.ts:Tauri 适配- 读取
TAURI_DEV_HOST环境变量 envPrefix添加TAURI_server.watch.ignored排除src-tauri/
- 读取
Patterns to follow: 现有 api/base.ts 的 BaseApiClient 模式;现有 Design Token 体系
Test scenarios:
- 浏览器模式:所有 API 调用正常工作(相对路径不变)
- Tauri 模式:
initApiBaseURL()设置正确的http://127.0.0.1:{port} - Tauri 模式:WebSocket 连接到正确的
ws://127.0.0.1:{port}/api/v1/... - Splash 在后端就绪前显示,就绪后消失
- TitleBar 拖拽移动窗口,按钮功能正确
- 后端启动失败时显示错误信息
Verification: npm run tauri dev 启动后:Splash 显示 → 后端启动 → 主界面加载 → API 调用正常
U4. 系统托盘 + 单实例 + 窗口管理
Goal: 实现系统托盘、单实例锁和窗口关闭行为(最小化到托盘)。
Requirements: KTD-1
Dependencies: U2
Files:
src-tauri/src/tray.rs— 新增:系统托盘模块src-tauri/src/lib.rs— 修改:注册托盘、单实例插件、窗口事件src-tauri/Cargo.toml— 添加tauri-plugin-single-instance
Approach:
-
系统托盘(
tray.rs):- 菜单项:显示主窗口 / 分隔线 / 退出
- 左键点击托盘图标:显示并聚焦主窗口
- 退出菜单项:先
stop_backend(),再app.exit(0)
-
单实例锁:
- 注册
tauri-plugin-single-instance - 第二个实例启动时:聚焦已有主窗口
- 注册
-
窗口关闭行为:
CloseRequested事件中api.prevent_close()+window.hide()- 窗口隐藏到托盘而非退出
-
Splash → Main 切换:
start_backend成功后,Rust 侧关闭 splash 窗口、显示 main 窗口
Patterns to follow: Tauri 2.x tray API 文档
Test scenarios:
- 点击关闭按钮后窗口隐藏,托盘图标仍在
- 托盘"显示"菜单恢复窗口
- 托盘"退出"菜单停止后端并退出应用
- 左键点击托盘图标恢复窗口
- 启动第二个实例时聚焦已有窗口
Verification: 完整的窗口生命周期测试:启动 → 关闭到托盘 → 从托盘恢复 → 托盘退出
U5. PyInstaller 打包脚本 + Python 侧适配
Goal: 创建 PyInstaller 打包脚本,Python 后端支持 --port 0 并输出端口信息。
Requirements: KTD-2, KTD-3
Dependencies: U2
Files:
scripts/build-backend.sh— 新增:PyInstaller 打包脚本scripts/build-backend.ps1— 新增:Windows 版打包脚本src/agentkit/cli/main.py— 修改:gui命令支持--port 0src/agentkit/server/runner.py— 修改:uvicorn 启动后输出AGENTKIT_PORT=XXXXX
Approach:
-
Python 侧适配:
gui命令的--port参数支持0(让 OS 分配随机端口)- uvicorn 启动后,在 lifespan startup 中检测实际绑定端口
- 通过 stdout 输出
AGENTKIT_PORT={port}(flush=True),供 Rust 解析 - 当
--port 0时,host 默认改为127.0.0.1(仅本地访问,安全)
-
PyInstaller 打包脚本:
--onefile模式打包--name agentkit-server命名- 包含必要的
--hidden-import(uvicorn.logging, agentkit.server 等) --add-data包含 agentkit.yaml 和 configs 目录- 输出到
src-tauri/binaries/并添加平台后缀
-
平台后缀命名:
- macOS ARM:
agentkit-server-aarch64-apple-darwin - macOS Intel:
agentkit-server-x86_64-apple-darwin - Windows:
agentkit-server-x86_64-pc-windows-msvc.exe - Linux:
agentkit-server-x86_64-unknown-linux-gnu
- macOS ARM:
Patterns to follow: 现有 agentkit gui 命令的启动流程
Test scenarios:
python -m agentkit gui --port 0启动后 stdout 输出AGENTKIT_PORT=XXXXX- PyInstaller 打包的二进制能独立运行
- 打包的二进制支持
--port 0和AGENTKIT_GUI_MODE=1 - 打包的二进制在无 Python 环境的机器上能运行
Verification: 在当前平台执行 scripts/build-backend.sh,产物放入 src-tauri/binaries/,npm run tauri dev 能通过 sidecar 启动后端
U6. 跨平台 CI 构建
Goal: 配置 GitHub Actions 自动构建 Windows/macOS/Linux 安装包。
Requirements: KTD-1
Dependencies: U1, U5
Files:
.github/workflows/release-desktop.yml— 新增:桌面客户端发布工作流
Approach:
- 触发条件:推送
v*tag - 构建矩阵:macOS (aarch64 + x86_64)、Windows (x86_64)、Linux (x86_64)
- 每个平台步骤:
- Setup Node.js 20 + Rust stable + Python 3.11
- 安装 Linux 系统依赖(libwebkit2gtk-4.1-dev 等)
pip install pyinstaller+ 执行scripts/build-backend.shnpm ci+npm run tauri build
- 使用
tauri-apps/tauri-action@v0构建和发布 - 产物上传到 GitHub Release(draft)
Patterns to follow: Tauri 官方 GitHub Actions 模板
Test scenarios:
- 推送 tag 后工作流在所有 4 个目标上成功运行
- 产物正确上传到 GitHub Release
Verification: 手动触发工作流或推送 tag,检查 GitHub Release 页面
Risks & Dependencies
| 风险 | 影响 | 缓解 |
|---|---|---|
| PyInstaller 打包后部分依赖缺失 | 后端无法启动 | 逐步测试,添加 --hidden-import |
| Linux WebView 兼容性差异 | GUI 渲染异常 | 测试主流发行版(Ubuntu 22.04+),文档说明依赖 |
| Python sidecar 启动慢(3-5s) | 用户等待时间长 | Splash 加载画面 + 进度反馈 |
| macOS 签名/公证缺失 | 用户安装时被 Gatekeeper 阻止 | 延迟到后续迭代,文档说明绕过方法 |
| Tauri 2.x API 变更 | 代码需调整 | 锁定 Tauri 2.x 稳定版 |
Assumptions
- 用户机器上有 WebView2(Windows 10+ 自带)、WebKit(macOS 自带)、WebKitGTK(Linux 需安装)
- Python 后端不需要 GPU 加速或其他特殊硬件
- 单用户本地使用场景,不需要多用户认证
- 首个版本不需要应用签名和公证
Open Questions
- 自动更新服务器的部署方案(S3 / GitHub Releases / 自建)— 延迟到后续迭代
- 是否需要支持 Linux ARM64 — 视用户需求决定
- PyInstaller 产物体积优化(是否排除不必要的依赖)— 实现时评估