fischer-agentkit/docs/plans/2026-06-13-004-feat-tauri-d...

18 KiB
Raw Blame History

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 启动后自动打开浏览器),用户需要:

  1. 手动启动后端进程
  2. 在浏览器中操作,缺乏原生体验(无系统托盘、无桌面集成、无自动更新)
  3. 无法像桌面应用一样安装、启动、关闭

竞品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=XXXXXRust 侧解析后通过 Tauri IPC 传递给前端。避免端口冲突,无需用户配置。

KTD-4: 前端最小适配策略。 仅修改 api/base.ts(动态 baseURLApp.vueSplash 启动流程),新增 api/tauri.tsTauri 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:

  1. 在项目根目录初始化 Tauri 2.xnpm create tauri-app@latest 或手动创建 src-tauri/ 目录
  2. tauri.conf.json 配置双窗口splash + mainmain 初始 visible: false
  3. build.beforeDevCommand 指向前端 dev 脚本,build.beforeBuildCommand 指向前端 build 脚本
  4. build.frontendDist 指向前端构建输出目录
  5. bundle.externalBin 声明 sidecar 二进制名
  6. 安装前端依赖:@tauri-apps/api@^2, @tauri-apps/plugin-shell@^2
  7. 验证 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 和 BackendState
  • src-tauri/Cargo.toml — 添加 regex 依赖

Approach:

  1. 定义 BackendState 结构体:port: Mutex<Option<u16>>, pid: Mutex<Option<u32>>
  2. 实现 start_backend 命令:
    • 通过 app.shell().sidecar("agentkit-server") 创建 sidecar 命令
    • 传入 --port 0AGENTKIT_GUI_MODE=1 环境变量
    • spawn 后监听 stdout/stderr用正则解析 AGENTKIT_PORT=(\d+)
    • 端口就绪后 emit backend-ready 事件
    • 带超时等待30s
  3. 实现 get_backend_port 命令:返回当前端口
  4. 实现 stop_backend 命令:发送 SIGTERMUnix或 taskkillWindows
  5. 实现 check_backend_health 命令HTTP GET http://127.0.0.1:{port}/api/v1/health
  6. lib.rs 中注册所有命令和 BackendState managed 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 在后端就绪后返回 true
  • stop_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 环境动态 baseURL
  • src/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 — 修改:集成 TitleBar
  • src/agentkit/server/frontend/vite.config.ts — 修改Tauri 环境适配

Approach:

  1. 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')
  2. api/base.ts:动态 baseURL

    • 新增 initApiBaseURL() 函数
    • Tauri 环境:从 getBackendPort() 获取端口,设置 apiBaseURL = http://127.0.0.1:{port}
    • 浏览器环境:apiBaseURL = ''(保持现有相对路径行为)
    • BaseApiClientrequest()createWebSocket() 方法使用动态 baseURL
  3. App.vueSplash 启动流程

    • 新增 loadingloadingProgress 响应式状态
    • onMounted 时:如果 isTauri(),调用 startBackend()initApiBaseURL()checkBackendHealth()
    • 加载完成前显示 SplashScreen,完成后显示 RouterView
    • 浏览器环境保持现有行为不变
  4. SplashScreen.vue:加载动画组件

    • 品牌 Logo + 加载进度条 + 状态文字("正在启动后端..."、"正在连接..."
    • 使用现有 Design Token 变量
  5. TitleBar.vue:自定义标题栏

    • data-tauri-drag-region 使标题栏可拖拽
    • 最小化/最大化/关闭按钮(关闭时隐藏到托盘)
    • 仅在 Tauri 环境中显示
  6. vite.config.tsTauri 适配

    • 读取 TAURI_DEV_HOST 环境变量
    • envPrefix 添加 TAURI_
    • server.watch.ignored 排除 src-tauri/

Patterns to follow: 现有 api/base.tsBaseApiClient 模式;现有 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:

  1. 系统托盘tray.rs

    • 菜单项:显示主窗口 / 分隔线 / 退出
    • 左键点击托盘图标:显示并聚焦主窗口
    • 退出菜单项:先 stop_backend(),再 app.exit(0)
  2. 单实例锁

    • 注册 tauri-plugin-single-instance
    • 第二个实例启动时:聚焦已有主窗口
  3. 窗口关闭行为

    • CloseRequested 事件中 api.prevent_close() + window.hide()
    • 窗口隐藏到托盘而非退出
  4. 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 0
  • src/agentkit/server/runner.py — 修改uvicorn 启动后输出 AGENTKIT_PORT=XXXXX

Approach:

  1. Python 侧适配

    • gui 命令的 --port 参数支持 0(让 OS 分配随机端口)
    • uvicorn 启动后,在 lifespan startup 中检测实际绑定端口
    • 通过 stdout 输出 AGENTKIT_PORT={port}flush=True供 Rust 解析
    • --port 0host 默认改为 127.0.0.1(仅本地访问,安全)
  2. PyInstaller 打包脚本

    • --onefile 模式打包
    • --name agentkit-server 命名
    • 包含必要的 --hidden-importuvicorn.logging, agentkit.server 等)
    • --add-data 包含 agentkit.yaml 和 configs 目录
    • 输出到 src-tauri/binaries/ 并添加平台后缀
  3. 平台后缀命名

    • 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

Patterns to follow: 现有 agentkit gui 命令的启动流程

Test scenarios:

  • python -m agentkit gui --port 0 启动后 stdout 输出 AGENTKIT_PORT=XXXXX
  • PyInstaller 打包的二进制能独立运行
  • 打包的二进制支持 --port 0AGENTKIT_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:

  1. 触发条件:推送 v* tag
  2. 构建矩阵macOS (aarch64 + x86_64)、Windows (x86_64)、Linux (x86_64)
  3. 每个平台步骤:
    • Setup Node.js 20 + Rust stable + Python 3.11
    • 安装 Linux 系统依赖libwebkit2gtk-4.1-dev 等)
    • pip install pyinstaller + 执行 scripts/build-backend.sh
    • npm ci + npm run tauri build
  4. 使用 tauri-apps/tauri-action@v0 构建和发布
  5. 产物上传到 GitHub Releasedraft

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

  • 用户机器上有 WebView2Windows 10+ 自带、WebKitmacOS 自带、WebKitGTKLinux 需安装)
  • Python 后端不需要 GPU 加速或其他特殊硬件
  • 单用户本地使用场景,不需要多用户认证
  • 首个版本不需要应用签名和公证

Open Questions

  • 自动更新服务器的部署方案S3 / GitHub Releases / 自建)— 延迟到后续迭代
  • 是否需要支持 Linux ARM64 — 视用户需求决定
  • PyInstaller 产物体积优化(是否排除不必要的依赖)— 实现时评估