Co-authored-by: Subharup Nandi <Subharup-31@users.noreply.github.com> Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
11 KiB
description, icon
| description | icon |
|---|---|
| 桌面宿主 (`app/src-tauri/`) —— Tauri v2 + WebView、IPC、嵌入式核心生命周期、核心桥接。 | desktop |
Tauri Shell (app/src-tauri/)
OpenHuman 的桌面宿主:Tauri v2 + WebView、IPC 命令、窗口管理,以及桥接到嵌入式 openhuman-core Rust 运行时(核心 JSON-RPC)。它不会重复完整的领域栈;那部分存在于仓库根目录的 Rust crate 中(openhuman_core、src/main.rs)。
职责
- Web UI。从
app/dist加载 Vite 构建(或开发服务器,端口 1420)。 - IPC。暴露一小套明确的 Tauri 命令(见 Commands)。
- 核心生命周期。启动进程内核心服务器,并通过
core_rpc_relay代理 JSON-RPC。 - 磁盘上的 AI 提示。从资源 / 开发 cwd 解析捆绑的
src/openhuman/agent/prompts,用于ai_get_config/write_ai_config_file。 - 窗口 + 托盘。桌面窗口行为和系统托盘(见
lib.rs)。
核心进程模型
app/package.json 的 core:stage 现在有意保持为 no-op,仅用于脚本兼容性。桌面应用会在进程内链接核心,因此本地构建不再需要在 app/src-tauri/binaries/ 下 staging openhuman-core-* sidecar。
卡死进程恢复
正常应用退出从 RunEvent::ExitRequested 运行 teardown:CEF 关闭前先关闭子 webview,触发嵌入式核心的 cancellation token,最终进程扫描在短暂的宽限期后向直接子进程发送 SIGTERM,然后升级使用 SIGKILL 处理顽固进程。扫描摘要记录为 [app] sweep: term=N kill=M total=K;任何非零 kill 计数都是警告,意味着子进程忽略了优雅关闭。
在 macOS 上,硬退出(强制退出、SIGKILL、渲染器崩溃)可能跳过正常的 teardown。下一次启动在 CEF 缓存 preflight 之前运行启动恢复:它列出可执行路径属于正在启动的 .app/Contents 的 OpenHuman 进程,跳过当前进程,发送 SIGTERM,短暂等待,然后对仍然匹配相同 pid+command 的顽固进程发送 SIGKILL。日志使用 [startup-recovery] 前缀。
当设置了 OPENHUMAN_CORE_REUSE_EXISTING=1 时(以便手动 CLI-core 复用仍然有效),以及当 CEF SingletonLock 被实时进程持有时(以便正常的 second-instance 路径可以在不杀死已运行应用的情况下失败),启动恢复跳过。Tauri 命令 process_diagnostics_list_owned 返回当前拥有的进程列表;macOS 实现是 bundle 作用域的,Linux/Windows 目前返回空。
Tauri Shell 架构 (app/src-tauri/)
概述
app/src-tauri crate(Rust 包 OpenHuman,二进制文件 OpenHuman)是一个仅限桌面的宿主。它嵌入 React UI,注册插件(深度链接、打开器、OS、通知、自动启动、更新器),管理主窗口和托盘,并中继 JSON-RPC 到嵌入式核心服务器。
非桌面目标在编译时失败(lib.rs 中的 compile_error!)。
目录布局(实际)
app/src-tauri/src/
├── lib.rs # `run()`、托盘/菜单动作、插件、`generate_handler!`、核心启动
├── main.rs # 二进制入口
├── core_process.rs # CoreProcessHandle、嵌入式核心服务器任务
├── core_rpc.rs # 核心 JSON-RPC 的 HTTP 客户端
├── commands/
│ ├── mod.rs # 重新导出
│ ├── core_relay.rs # `core_rpc_relay`、服务管理的核心引导
│ ├── openhuman.rs # Daemon 宿主配置、systemd 风格服务辅助函数
│ └── window.rs # 显示/隐藏/最小化/关闭窗口
└── utils/
├── mod.rs
└── dev_paths.rs # 解析捆绑的 AI 提示路径
此树中没有 src-tauri/src/services/session_service.rs;会话语义在 Web 层 + 后端 + 核心中按适用情况处理。
数据流:UI → 核心
React (invoke)
→ core_rpc_relay { method, params, serviceManaged? }
→ core_rpc::call HTTP POST 到 OPENHUMAN_CORE_RPC_URL
→ 嵌入式 openhuman 核心服务器
core_process.rs 中的 CoreProcessHandle 拥有嵌入式服务器任务;commands/core_relay.rs 可选地在 relay 之前确保服务管理的核心正在运行。
窗口和托盘行为
- 壳层在启动时创建托盘图标,并将动作连接到打开主窗口或退出。
- 在 daemon 模式(
daemon/--daemon)下,主窗口在启动时隐藏,可以从托盘动作重新打开。 - 在 macOS 上,
RunEvent::Reopen也会恢复并聚焦主窗口。 - Windows 和 Linux 使用相同的托盘动作(
Open OpenHuman、Quit),某些 Linux 设置上有桌面环境特定的托盘渲染差异。
捆绑资源
tauri.conf.json 捆绑 ../../skills/skills 和 ../../src/openhuman/agent/prompts,使技能和提示 markdown 随应用一起发布。
相关
- IPC 表面:见下方的 Commands 部分
- HTTP 桥接:见下方的 Core bridge & helpers 部分
- Rust 领域(实现):仓库根目录
src/openhuman/、src/core_server/
Tauri IPC 命令 (app/src-tauri)
所有命令都在 app/src-tauri/src/lib.rs 中的 tauri::generate_handler![...] 内注册(桌面构建)。下方名称是 Rust 命令名称(在 JS 中通过 serde 应用 camelCase)。
Demo / 诊断
| 命令 | 用途 |
|---|---|
greet |
Demo 字符串(生产中可安全移除) |
AI 配置(捆绑提示)
| 命令 | 用途 |
|---|---|
ai_get_config |
从捆绑或开发 src/openhuman/agent/prompts 下解析的 SOUL.md / TOOLS.md 构建 AIPreview |
ai_refresh_config |
与 ai_get_config 相同的读取路径(刷新 hook) |
write_ai_config_file |
在仓库 src/openhuman/agent/prompts 下写入单个 .md(开发 / 安全文件名检查) |
核心 JSON-RPC 中继
| 命令 | 用途 |
|---|---|
core_rpc_relay |
Body: { method, params?, serviceManaged? } → 转发到本地 openhuman-core HTTP JSON-RPC (core_rpc.rs) |
从前端使用 app/src/services/coreRpcClient.ts (callCoreRpc)。
窗口管理
来自 commands/window.rs(名称可能略有不同;见 lib.rs):
| 命令 | 用途 |
|---|---|
show_window |
显示主窗口 |
hide_window |
隐藏主窗口 |
toggle_window |
切换可见性 |
is_window_visible |
查询可见性 |
minimize_window |
最小化 |
maximize_window |
最大化 |
close_window |
关闭 |
set_window_title |
设置标题字符串 |
OpenHuman daemon / 服务辅助函数
来自 commands/openhuman.rs(见源码获取精确 payload):
| 命令 | 用途 |
|---|---|
openhuman_get_daemon_host_config |
读取 daemon 宿主偏好设置(例如托盘) |
openhuman_set_daemon_host_config |
持久化 daemon 宿主偏好设置 |
openhuman_service_install |
安装后台服务(平台特定) |
openhuman_service_start |
启动服务 |
openhuman_service_stop |
停止服务 |
openhuman_service_status |
查询状态 |
openhuman_service_uninstall |
卸载服务 |
屏幕共享选择器(CEF / macOS)
来自 screen_capture/mod.rs。支持 webview_accounts/runtime.js 中的页面内 getDisplayMedia shim。会话门控:shim 必须在成功枚举/缩略图捕获之前用实时用户手势打开会话。见 issue #713(选择器 UX)+ #812(会话门控)。
| 命令 | 用途 |
|---|---|
screen_share_begin_session |
从账户 webview 打开 30s 会话,在 navigator.userActivation.isActive 手势之后。返回 { token, sources }。每个账户限速 10/分钟。 |
screen_share_thumbnail |
将单个来源的缩略图捕获为 base64 PNG。需要 live token 和会话颁发的 id。仅 macOS;其他平台返回错误。 |
screen_share_finalize_session |
关闭会话。由 shim 在 Share 或 Cancel 时调用;使用未知/过期 token 安全调用(no-op)。 |
已移除 / 不存在
以下命令不存在于当前的 generate_handler! 列表中:exchange_token、get_auth_state、socket_connect、start_telegram_login。认证和 socket 在 React 应用和 核心 进程中处理,而非通过这些 IPC 名称。
示例:核心 RPC
import { invoke } from "@tauri-apps/api/core";
const result = await invoke("core_rpc_relay", {
request: {
method: "your.rpc.method",
params: { foo: "bar" },
serviceManaged: false,
},
});
见 app/src-tauri/src/lib.rs 获取权威列表。
Core bridge & helpers (app/src-tauri)
本文档替代了旧的 "SessionService / SocketService" 拆分。Tauri crate 不嵌入重复的 Socket.io 服务器或 Telegram 客户端;相反,它专注于对 openhuman-core 二进制文件的进程管理和 HTTP JSON-RPC。
CoreProcessHandle (core_process.rs)
- 解析
openhuman-core可执行文件(staging 在binaries/下或PATH/ 开发布局中)。 - 启动或附加到核心进程并暴露其 RPC URL (
OPENHUMAN_CORE_RPC_URL)。 - 在
lib.rs的应用设置期间使用 (app.manage(core_handle))。
core_rpc (core_rpc.rs)
- 核心 JSON-RPC 表面的 HTTP 客户端(localhost)。
- 由
core_rpc_relay使用,以转发前端的method+params。
commands/core_relay.rs
core_rpc_relay。确保核心正在运行(进程内句柄或服务管理路径),然后调用core_rpc。ensure_service_managed_core_running。当 RPC 不可用时引导 systemd/launchd 风格服务(核心 CLI 内的平台特定行为)。
commands/openhuman.rs
- Daemon 宿主 JSON 配置(例如托盘可见性),位于应用数据目录下。
- 为 openhuman 后台服务提供 install/start/stop/status/uninstall 辅助函数。
utils/dev_paths.rs
- 解析 AI preview 的开发和捆绑资源路径下的
src/openhuman/agent/prompts。
utils/tauriSocket.ts(前端)
不在 src-tauri 中,但与 shell 配对:React 应用监听镜像 Rust 端客户端 socket 活动的 Tauri 事件。见 app/src/utils/tauriSocket.ts 和 前端服务 章节。