架构
面向开发者的整体概览。更轻量的入门见核心概念。
连接与媒体路径
浏览器与远端设备通过信令服务交换 SDP / ICE,并用 STUN/TURN 收集候选。它们优先直连 WebRTC P2P,仅当 NAT 穿透失败时回退到 TURN 中继。信令与 TURN 内置于 server。终端特意与 WebRTC 数据通道分离,使用独立的鉴权 WebSocket。
进程模型(service-daemon)
ServiceDaemon(SYSTEM / root)持有 WebRTC 连接、信令与子进程;它为每个桌面会话启动一个 SessionWorker,负责采集、编码、输入、文件与剪贴板。对等连接位于守护进程,因此 worker 能在用户切换时重启而不中断浏览器连接。
Daemon 与 worker 使用三条独立传输:双向 event pipe 承载信令和控制,单向 media pipe 承载编码后的音视频,双向 file pipe 承载文件命令和数据块。便携 default 与 desk-server 模式复用同一条逻辑 daemon/worker 路径,只是改用进程内通道。
AI 诊断流水线
中心编排器按照 采集 → 脱敏 → 模型 → 展示 的顺序运行;被控端脱敏失败会立即中止请求。模型可以建议命令,但只有经过认证的 owner 才能批准完整预览;被控端收到密封计划后仍会复校再执行。MCP 服务始终只读。见 AI 安全模型。
技术栈
后端——Rust(Edition 2024,1.90+)、Actix-Web 4.11、webrtc-rs 0.17、Actix-Session、Utoipa 5(OpenAPI)、turn 0.17、Prometheus。
前端——React 19、TailwindCSS + Shadcn UI(Radix)、Vite 7、Kubb(OpenAPI → React Query / TS)、TypeScript 5.9、xterm.js 5.5、TanStack Query v5。
多媒体——采集经 DXGI / WGC(Windows)、X11 / Wayland + PipeWire(Linux);编码经 X264 / OpenH264 / VP8 / VP9 / AV1;音频经 WASAPI / ALSA / PipeWire + Opus。
crate 级别细节见模块地图。
AI 助手工具标识与参数
子助手的 task_id 直接使用任务的紧凑原生 ID(t_ 加 22 个 URL-safe Base64 字符)。创建、查询、等待、读取、取消和调整任务使用相同值,不分配 t1、t2 别名,也不恢复另一份 UUID。
模型用已观察到的 ID 选择对象和结果,不需要抄写完整引用、协议版本或 SHA-256。文本修改/删除使用 file_version_id;Gmail 附件使用 artifact_result_id;Gmail/Slack 精确发送使用 handoff_result_id。文档操作使用 target_id,Office 选择读取使用 document_id;新文档副本的目录由已批准的 output.directory_request_id 恢复,只有一个可用目录时可省略。Word 报告引用网页搜索时,选择 web_search_result_id 和该结果中的 web_source_ids,标题和 URL 由服务端恢复。
这些短引用只定位当前会话里的原始证据,不代表授权。服务端先恢复确切的对象、完整摘要、原草稿正文及固定默认值,再冻结审批输入;设备继续核验版本、身份和操作范围。引用不会自动指向更新的结果。过期、已清除、错类型、重复或找不到的引用会拒绝执行。发送仍需独立的一次性确认,结果未知不会自动重试。原始回执、完整摘要和恢复信息继续保存;模型读取外置 JSON 附件时使用同一份简化视图。
自然语言目标、子任务和定时提示按 Unicode 字符限制;文件、正文、命令和原生输入另有明确的 UTF-8 字节限额。格式错误返回字段路径、约束和按当前工具定义生成的结构示例。默认参数由服务端在审批前固定,示例不会替代真实对象 ID。滚动优先使用命名方向与正数 amount:语义 UI 的 up/down/left/right 配合 1(小幅)或 2(大幅);后台输入的 up/down 配合窗口像素距离,并保留 position。斜向滚动仍可用原有数值轴,但不能混用方向参数。
原生标识与对象引用
助手自己创建的任务、消息、附件、审批/目录请求、预览及定时任务直接使用紧凑的原生 ID,后续查询、等待、取消和重试使用同一个值,不额外建立短 ID 到长 UUID 的映射。需要跨会话唯一的 ID 保留完整标识强度,通常包含类型前缀和 22 个编码字符;结果内的网页来源直接使用稳定序号。
设备签发的 UI、浏览器、文件/文档对象以及不透明分页游标保留完整原始身份,由同一会话引用状态提供便于复制的短引用。模型应复制工具实际返回的 ID,不能根据名称、位置或其他会话中的编号猜测。编号不会改指另一对象;引用失效时应重新读取对应资源。正文、路径、URL、用户提供的业务标识及模型协议的关联 ID 不做全局替换。
内联结果、附件分页、历史参数、权限申请和 AI 审批使用一致的表示。摘要压缩不等于附件内容被删除,仍有效的来源可继续解析;已删除或被存储清理淘汰的内容不可恢复。分页只绑定原内容、查询及相关投影,新增无关对象引用不会使当前分页游标失效。会话删除后对应映射一并删除。
AI 助手上下文与执行恢复
owner 选择的终端和窗口附件只保存有界展示元数据、不透明设备引用及来源标签,不保存正文;选择附件不授予执行权限。开源 Signal 在 SQLite 中原子保存每次新元数据操作及其首次回执。同一请求重试返回首次 changed 值,重连或模型配置移除后也一样,不再次改变附件、更换模型目的地、延长期限或重新激活已撤销选择;同一请求 ID 携带不同操作内容则拒绝。撤销已有附件不要求配置模型。活动回合期间拒绝新的附件变更,原回执在当前 owner 和目标检查通过后仍可重放。回执不代表附件当前状态,应刷新权威会话快照。真正读取时仍由原设备校验引用;实际读取以设备返回结果为准。
若保留的选择元数据没有原回执,Signal 不从当前状态反推首次结果,而是拒绝该请求 ID;刷新快照后可使用新请求 ID 提交新的显式操作。升级不会重写既有附件或权限。
实时能力选择在 Signal 与 Manager 上共用 UpdateAiAssistantContext(638)→ AiAssistantContextUpdated(639)。选择只保存绑定当前 worker 代次、模型目的地和 readiness 期限的有界元数据,不授予工具权限,也不包含截图或文档正文;CurrentScreen 仍是显式单回合输入,不能通过 638 持久保存。完整相同请求返回首次 changed(包括 false),不刷新元数据;同 ID 更换选择时拒绝。清空实时选择不要求模型可用,也不删除文件或终端附件。即使租约过期,活动回合仍拒绝新选择更新,须先由原恢复流程收尾。成功与失败都保留传输和客户端请求关联。当前状态应读取会话快照,不能把历史回执视为当前仍在选择;
对于新的AI助手输入,Signal 将精确读取工具与对象选择随消息原子保存。同一消息 ID 更换正文、来源标签、主体或选择时拒绝;权限续跑恢复原选择和截止时间,不因后来新增附件或工具恢复 ready 而扩大读取范围。没有原对象选择记录的旧输入不会自动补造选择。对象读取发送前、收到结果后都会复核当前输入和附件状态;文件、表格、终端及 iWork batch 使用原引用、请求与附件中更小的上限,以及原模型目的地和来源标签,不用展示名称判断文件类型。过期、撤销或已被追问替代的选择正常拒绝,超限或携带图片的对象结果不会重新贴标签后交给模型。这些检查不替代 capability grant 和设备端引用校验。
当可信运行时明确提供输入来源标签时,共享助手循环保留这些来源,不再追加会话中其它无关的 active 附件;模型输出和 owner 消息的传递来源仍会记录。来源记录本身不授予新的读取或外发权限。
下述“原输入选择”限制针对用户附加对象的读取路径。会话已批准目录和可信文件结果引用是另两种显式选择路径,读取前仍须验证当前目录授权、精确输入和来源证据,并单独申请操作权限;不是读取设备上的任意文件。
工具执行结果、用户消息和 AI 回答是会话历史,不会因为时间经过或授权到期而从模型上下文中清除。只有达到上下文容量阈值时才进行窗口裁剪或摘要压缩;原始聊天记录仍保留。历史结果记录当时发生的事实,不代表设备当前状态,也不授予再次执行权限。新操作仍校验授权期限、目标身份和必要的最新状态。模型目的地或来源授权变化仍会限制对应内容的发送。
Signal 权限决定重试在当前调用者和在线目标校验通过后返回首次决定,即使当前 readiness 不可用、授权已过期/撤销或原输入已被新问题替代也一样。完整决定的各项内容和限制必须与首次一致,条目顺序可以不同。重试不新签授权、不恢复次数、不改会话,也不另起模型续跑;原请求或决定记录缺失/损坏时,不能从当前批准状态反推回执。响应 state 是历史决定回执,不是当前权限或已续跑的证明。
新决定还会在同一 SQLite 事务保存续跑领取记录。Signal 周期扫描尚未领取的续跑,不要求手机或原 HTTP 请求持续在线;等待唯一可确定的认证目标及新鲜 readiness,再检查原输入、模型目的地和当前授权。会话领取与 started 状态一起提交,重复唤醒不能再次启动同一续跑。新问题会替代尚未领取的旧续跑;已经 started 的续跑在崩溃后不自动重跑,而是核对原租约与动作账本。这些恢复检查不延长引用、授权或来源留存。
AI助手接受运行中追问时,共享循环会在首次和最终保存边界重新检查输入版本,避免把旧回答当成新需求的结果。普通存储失败仍按错误处理,不伪装成追问替代;撤回旧回答也不表示已开始的设备动作取消成功。
共享执行接口区分运行时确认的“未执行”和用户拒绝:若执行后端确认动作在派发前结束,循环记录未执行原因并停止本回合后续写操作,不将其显示为用户取消。这个内部结果本身不授予执行权限,也不代表所有执行后端已经具备相同的持久化恢复能力。
执行后端也可提供已经验证的原始结果标签。共享循环验证结果字节与标签匹配后原样保留,不在投递时重新生成来源或延长有效期;不匹配时拒绝使用结果且不确认投递已消费。该标签不隐含模型外发授权。开源 Signal 为已绑定的副作用 Computer Action 保存原始完成回执,包括前台等待者退出后收到的迟到结果;前台执行、主动等待和完成发布使用同一套经过校验的结果投影。旧命令结果与内联浏览器读取保留既有标签路径。
Computer Action 取得明确执行器接纳、且已有冻结的后台执行策略时,可以在前台预算结束后继续作为同一个原任务运行。owner 快照一致读取对话、授权和任务状态;任务变化推进展示序号,不使运行回合的租约失效。完成结果保存后才确认消费,超期先变为未知,等待真实结果对账。有界、无工具的模型解释必须沿用仍有效的原模型目标和上下文外发选择;Secret、新输入、上下文/模型变化、标签过期或 replay 不可用均不能被静默重新授权。自动解释被拒绝时,owner 仍可看到原始结果。这些 OSS 原任务现已接通持久 owner 取消:只向原连接重试停止,不重复动作,也不迁移到重连连接。停止确认不是终态,只有原生暂停回执才显示已取消,迟到成功或失败仍以原结果为准。
带回执的终态不等于成功:后端确认失败时,共享循环仍按原标签保存结果,并在保存成功后确认投递,但工具状态显示失败、同组后续动作停止。主动等待得到原动作的失败回执时也遵循这一规则,不用新的等待调用替换原调用身份。若当前工具组尚未结束,先保留未消费回执,后续独立等待再取原结果;结果未知仍是未知,不因收到消息就被改成失败或成功。
事务型执行后端可返回绑定原输入、租约、调用和保存后会话版本的回执。共享循环只接受本执行者自己的连续版本推进;即使事务之后报错,也保留该推进以便正确保存错误。它不会读取最新版本来绕过撤销或新输入造成的并发冲突,也不是工具执行授权。开源 Signal 默认仍走原执行入口,不需要为此引入 Manager 的共享存储。
个人AI助手与 Manager 共用独立的编译期策略版本,不受无关组织策略计数器影响。旧版本审批不能自动升级并续跑;发送新的明确请求后,新回合才采用当前策略,历史消息和旧授权不会被重签或补回次数。自动续跑和授权签发都必须匹配当前版本,版本一致也不替代目标设备 readiness 与授权撤销检查。普通终端 AI 助手 的策略语义不变。
浏览器 Provider 使用两端共享的闭集输入预检:输入大小受限,选中 BrowserSurface 必须未过期,动作范围与风险由服务端派生。通用填表和元素激活仍按 InputFallback 处理,Gmail/Slack 草稿交接不会变成发送操作。预检通过不是执行授权,后续仍需原有 grant、外发检查、持久化派发与目标设备校验。
桌面语义操作的执行入口、权限申请和 grant 签发共用严格输入解码:对象和动作须符合当前工具定义及设备能力。应用授权可包含 Toggle 动作,但这不表示每个原生控件都支持它;原目标设备继续校验引用到期、会话身份和实际支持动作。中央校验不能替代 Accessibility/UIA 的原生执行与读回,也不绕过本地权限、writer lease 或输入抢占。
中心下发的 Computer Action 不要求浏览器保持远程桌面连接:在已有单 worker 的便携/DeskServer 路径中,可以直接交给该 worker;启用多会话路由时仍必须有明确的会话绑定,不能猜选桌面。动作处理器在交付 worker 前拒绝请求时,使用原请求关联的 ComputerActionCompleted 报告“确定未开始”,而非等待超时;这不撤销其他动作,也不放宽授权、readiness 或本地能力限制。
受信中心可用 CancelComputerAction 请求停止原 Computer Action。daemon 校验授权后将批准者与完整 action/work/generation 传给原 worker;无明确会话时不猜选桌面。ComputerActionStateReported 的 CancelRequested 只确认已使匹配 writer 失效,不表示系统调用已撤销或动作未发生。后续 adapter 步骤被阻止,但仍以原完成回执或未知结果为准;writer 被取消、抢占或到期后,必须等待原操作释放才允许下一写入者。daemon 与 worker 必须使用同一构建,取消 IPC 的批准者字段不能与旧布局混用。
AI助手的 live Office、Numbers、Pages 和 Keynote 读取现将所选设备签发的文档引用随原输入保存,权限续跑不会重新选择较新的前台文档。派发前与收到结果后都会检查原输入、模型目的地、当前 worker/引用及原期限;目标变化或过期时拒绝,不向模型投递其正文。Office 授权与 live iWork 一样使用精确对象资源合同。结果来源标识原目标但不外露可执行 token,留存不能超过原期限;iWork batch 仍走文件附件。live 输入在接收和读取前还必须匹配当前 active 的持久 638 选择;权限等待期间撤回后不得续跑且不消耗 grant,后来重新选择也不能复活旧输入。Android/iOS 严格关联 639,断线后只重试同一个 client request 身份。