AIDAWORK / ARCHITECTURE

Desktop:进程边界与本机能力

独立图页 ↗
机制说明(SoT)图是辅读 · 结论以说明与证据为准

Desktop session 表达 Main 持有的本机执行上下文,Server session 表达 Agent 会话;跨边界时需要明确配对。本机 PluginHost 管插件投影和回执。普通文件操作属 Local File V4 架构族(Desktop 协议 v3 起不再有独立的 Local File wire 版本,path-free 不变):账本在 Agent,执行与附件组装在 Main;Renderer 只提交无路径的草稿意图。

本页可直接往下读完整机制说明,不需要「演示 / 播放故事」。术语不熟先看 术语表。

先读机制说明,结论以说明与证据为准 · 基于固定代码版本核验 · 部署状态另行确认

机制说明(全文)

Desktop:进程边界与本机能力

沿 Main 边界阅读本机能力

Desktop session 表达 Main 持有的本机执行上下文,Server session 表达 Agent 会话;跨边界时需要明确配对。本机 PluginHost 管插件投影和回执。普通文件操作属 Local File V4 架构族(Desktop 协议 v3 起不再有独立的 Local File wire 版本,path-free 不变):账本在 Agent,执行与附件组装在 Main;Renderer 只提交无路径的草稿意图。

这些宿主共同位于本机责任范围,不意味着它们共享同一状态机。chat 提交与观察统一走 Work 路径(register-runtime-v2-ipc 已删除);runtime-v2.1 入口不再放行(见下表 RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED)。

Gateway 协议硬门族(426 / fail-closed)

钉点 Agent e2adc9a3c325 / Desktop 8eecd12081db 起,Desktop↔Agent 只剩一个协议版本 DESKTOP_PROTOCOL_VERSION = 3(Agent ADR-0090 D4、Desktop ADR-0087 D3:版本即能力,不再协商 feature token),所有 Desktop 准入边界对非 3 的版本统一返回 426 DESKTOP_UPGRADE_REQUIRED(chat 受理按 ADR-0093 只在声明了本机执行协议或携带本机执行载荷时检查,见下表),body { code, message: "请升级 AidaWork 客户端。", expectedProtocolVersion: 3 },Desktop 映射到升级提示、不做容错解码。原 desktop_protocol_version_required、local_execution_recovery_protocol_upgrade_required、LOCAL_FILE_PROTOCOL_UPGRADE_REQUIRED 三个码已删除。Interaction Kernel 与 Runtime Work 的协议门是另外两扇门,不要合并理解。

错误码 / 信号 入口 判定 阻断范围
DESKTOP_UPGRADE_REQUIRED chat POST /(头 X-AIDA-Protocol 有值且 ≠ 3;或没带头却携带本机执行载荷 localExecutor / localFilesV4 / assembleSubmittedLocalFileAttachments / pluginTask / pluginTools / userSkill;均审计 desktop_protocol_version_rejected);chat POST / /validate-local-executor / 路由预览的 localExecutor.version;本机执行回执、Local File 回执与投递、durable recovery GET /pending(头 Aida-Local-Execution-Protocol-Version)、桌面分发 版本 ≠ 3;载荷缺 version 按 schema 违规(不算升级信号) 整次 chat 提交 / 该端点
RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED chat POST 按提交 wire + policy 校验;取消提交、api-runs cancel、active-run 分别有独立门(见协议地图) 非支持的提交 wire;skill-v2 与 policy 不匹配另有码 该 Runtime/Run 路径
interaction_protocol_upgrade_required api-conversation-interactions 全路由中间件 头 Aida-Interaction-Protocol-Version 未接受(Kernel 现为协议 2) 该对话 Interaction API

ADR-0093(钉点 Agent e2adc9a3c325,状态 Proposed、代码已落地):本机执行协议只约束本机执行。chat POST 没带 X-AIDA-Protocol、请求体也没有本机执行载荷(清单 LOCAL_EXECUTION_CHAT_BODY_FIELDS)时,不再 426,进入 Runtime Work 协议检查和后续受理;这只证明通过协议门,最终工具集合仍须分别核验能力与执行绑定;这是为不做本机执行的客户端(如移动端第一阶段)准备的。Desktop 始终带头 3,行为不变;本机执行回执、Local File、durable recovery、桌面分发入口仍按 ADR-0090 D4 硬切。

载荷里没有合法的 localFileCapability 不再触发 426,只是本轮不注册 Local File V4 工具(localFileV4Admitted)。Desktop 侧 shared/generated/protocol-version.ts 由 Agent tool-client 生成;pending-read 恢复把 426 映射为 PENDING_LOCAL_READ_PROTOCOL_UPGRADE_REQUIRED。跨端(Desktop Electron / E2E)验收按两个 ADR 的记载尚未运行。

证据钉点:aida-agent e2adc9a3c325a258a88d68103de87e6630a3b676,aida-desktop 8eecd12081dbb5c725c1be3754dfaae7b845aa31。

证据与范围

  • aida-desktop · CONTEXT.md L1388–1418 · Dual session identity · 4346d79eb364(历史引用:该文件在上一钉点与当前钉点均不存在,未能复核;见 ATLAS-DEBT)

  • aida-desktop · apps/desktop/electron/plugin-host/plugin-host.ts L659–689 · listProjections · 4346d79eb364

  • aida-agent · docs/architecture/lifecycle-map.md L42–98 · e2adc9a3c325(历史引用:该文件在上一钉点与当前钉点均不存在,未能复核;见 ATLAS-DEBT)

  • aida-desktop · apps/desktop/electron/local-files-v4/assemble-submitted-attachments.ts L49–80 · assembleSubmittedLocalFileAttachments · 4346d79eb364

  • aida-desktop · apps/desktop/electron/agent-loop/register-runtime-work-ipc.ts L251–276 · submitSubmission · 4346d79eb364(register-runtime-v2-ipc 已删除)

  • aida-agent · packages/agent/src/runtime/work/run-work-admission.ts L16–57 · bindAdmittedWork · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L374–412 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L489–529 · chatBodyCarriesLocalExecution · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/request-schemas.ts L74–91 · LOCAL_EXECUTION_CHAT_BODY_FIELDS · e2adc9a3c325

  • aida-agent · docs/adr/0093-chat-admission-separates-runtime-and-local-execution-protocols.md L26–58 · 本机执行协议只约束本机执行 · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L381–421 · RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-conversation-interactions.ts L465–495 · interaction_protocol_upgrade_required · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-durable-local-execution-recovery.ts L66–72 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/protocol-version.ts L1–38 · DESKTOP_UPGRADE_REQUIRED · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L520–524 · desktopPayloadVersionUnsupported · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-local-execution-receipts.ts L42–47 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-local-file-v4.ts L82–87 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-desktop-distribution.ts L55–59 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-desktop · apps/desktop/shared/generated/protocol-version.ts L1–8 · DESKTOP_PROTOCOL_VERSION · 4346d79eb364

  • aida-desktop · docs/adr/0087-local-capability-convergence-and-protocol-v3.md L30–32 · DESKTOP_PROTOCOL_VERSION = 3 · 4346d79eb364

  • aida-agent · packages/tool-client/src/types/runtime-execution.ts L6–46 · RUNTIME_EXECUTION_PROTOCOL · e2adc9a3c325

结论来自固定版本的静态源码与合同阅读;实现存在、默认开关和生产启用分别判断。本站代码证据面板列出声明状态与具体限制。

远程 Desktop 设备目录(钉点 e2adc9a3c325 / 8eecd12081db)

  • 迁移 188 + DesktopExecutionDirectory:登记 desktop_execution_devices、online lease、continuation_context.remoteDesktop。
  • chat 可带 executionTarget / remote binding;无头本机载荷规则仍受 ADR-0093 约束。
  • 真机远程登记、租赁续期、跨设备执行 未核实。视图 remote-device。

Mermaid 实现图册

九张 Desktop 图:信任边界、持久提交 unknown、executor 租约、Plugin 条件产物、本机回执恢复、更新安装策略、Delivery UML、Stop 核对时序、artifact 输入物化时序。与服务端九张图对照;具体枚举与概念流程已分别标明。

Runtime 提交 wire 与原 Work identity

chat POST 的 Runtime 提交门接受缺省/空值(无 policy)、runtime-work-v1(无 policy),以及 runtime-work-skill-v2 且携带合法 skillExecutionPolicy;其他非空头为 RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED,头与 policy 不匹配为 RUNTIME_WORK_SKILL_POLICY_MISMATCH,均返回 426。原 Work binding 仍是 runtime-work-v1;取消提交、补充材料等路由单独判定,见协议地图。

证据:提交门 与 实际 chat POST 调用。

Desktop 实现图谱(固定代码快照)

基线:4346d79eb364b502ef87c0869a494dfed7964419,Desktop 0.2.5。下列图为代码阅读的结构化表达,不代表运行验收。D02 状态图与 D08 时序图使用实际 phase 名;UML 图区分类与接口,其余图为概念结构、调用时序或策略流程,不新增协议状态。

图索引

D01 信任边界:安装信任与资源授权分开

Desktop 实现图 D01

图形正在加载;下方源代码始终可读。

Mermaid 源代码
flowchart LR
  accTitle: Desktop 实现图 D01
  accDescr: Main 与 Renderer 和执行进程的权限边界,安装信任不等于资源授权或操作系统沙箱。
  R["Renderer / preload"]
  M["Electron Main"]
  A["Agent 服务"]
  V["Main Credential Vault"]
  I["installed capability 授权"]
  P["独立资源授权"]
  W["Plugin / Skill 进程"]
  F["本地文件与产物索引"]
  R -->|"受限 IPC"| M
  M -->|"当前身份绑定的请求"| A
  V -->|"Main 专用凭据"| M
  M --> I
  I -->|"identity + request + executor 检查"| W
  M --> P
  P -->|"Computer Use / 连接授权 / 文件操作"| F
  W -->|"Host API"| M
  M -->|"opaque ID 与私有路径映射"| F

不能把此图读成沙箱:安装后的执行不再等待通用 per-call/always-allow 确认,也不由 ClientAccessMode 决定(旧 PluginExecutionApprovalGate 与 directory-batch 已随 eb0f30dc 移除);但身份、原任务、包完整性、请求摘要检查仍存在。Computer Use 窗口许可、连接授权、typed user action 和本地文件 effects 各有自己的边界。批准运行的进程拥有 OS 用户文件权限与网络,working directory 不是 OS sandbox。

证据:apps/desktop/electron/installed-capability-authorization.ts;Skill 实际 wiring;Plugin 实际 wiring。

D02 持久提交与 unknown:实际 phase 的局部状态图

以下是 submission delivery phase 的有意局部视图,不是 Run 状态机;省略 queued/reply/rejected 等 admission outcome。图中的 accepted 是服务器接受原提交,不是业务执行成功。

Desktop 实现图 D02

图形正在加载;下方源代码始终可读。

Mermaid 源代码
stateDiagram-v2
  accTitle: Desktop 实现图 D02
  accDescr: 提交阶段保存原 command,结果未知只查询原提交,不自动重放。
  [*] --> prepared: prepare 冻结原始 intent 并更新 Store
  prepared --> sending: beginSending 唯一首次发送屏障
  prepared --> withdrawn: 发送前撤回
  sending --> accepted: 原 command 的有效 ACK
  sending --> unknown: recover 发现持久 sending
  unknown --> accepted: 查询并验证原 Message/binding
  unknown --> unknown: 查询仍 unknown
  note right of unknown
    不创建替代 command
    不重新发送物理提交
    404 / not_started 不授予重发
  end note
  note right of accepted
    保留原 binding
    不降级回 sending
  end note

这里的 Store 保存不等于强耐久落盘:当前实现先推进内存,加密磁盘发布为异步 best-effort,失败只告警且不写明文;图不保证断电后记录必然存在。见 Store 持久性边界。

身份切换/摘要不符是拒绝操作,不虚构一个 phase。Stop 使用独立 command,先 unresolved,再解析并一次性绑定原 rootRunId 为 prepared;未知 Stop 仅 queryStop。由于 Stop 与 submission 的建立条件不同,不把两者折叠成同一个状态机。

证据:提交一次物理发送;recover/accept 实际转换;发送与撤回屏障;原提交查询;Stop 绑定与查询。

单次发送屏障只约束仍保有的 Store 记录,不是跨崩溃或记录丢失的 exactly-once 保证。

D03 Desktop executor:租约与 inbox,不是第二个模型循环

Desktop 实现图 D03

图形正在加载;下方源代码始终可读。

Mermaid 源代码
sequenceDiagram
  accTitle: Desktop 实现图 D03
  accDescr: Desktop 注册租约并并行续约与拉取 inbox,原 effect owner 执行。
  participant Tick as Main lifecycle tick
  participant Host as DesktopExecutionHost
  participant Auth as 当前身份 owner
  participant API as Agent executor API
  participant Work as 原 Work coordinator
  participant Effect as 原 effect owner
  Tick->>Host: tick(已有连接时不重复启动)
  Host->>Auth: owner + registration
  Host->>API: GET capabilities
  Host->>API: POST self/lease
  API-->>Host: lease(验证 deviceId)
  par 心跳续约
    Host->>API: POST self/lease
    API-->>Host: 同 deviceId / leaseId
  and inbox 接收
    Host->>API: GET self/inbox(leaseId / revision / after)
    API-->>Host: 分页 items + ETag
    Host->>Work: accept(items, scopeDigest)
    Work->>Effect: 复用既有执行 owner
  end
  alt 身份变化
    Auth-->>Host: invalidate
    Host->>Host: generation++ / abort / clear
  else 连接故障
    Host->>Host: clear + 有界退避
    Note over Host,API: 不在普通网络失败时 DELETE,避免迟到删除误伤新租约
  end

心跳与接收并行,任一路失败会结束本连接;正常 close 才 best-effort 删除已捕获 lease。inbox 只是连接交付,不创造新的模型或 effect ledger。

证据:连接生命周期;注册/并行心跳/分页 inbox/释放。

D04 Plugin 条件产物:Worker 声明不能代替 Main 事实

Desktop 实现图 D04

图形正在加载;下方源代码始终可读。

Mermaid 源代码
sequenceDiagram
  accTitle: Desktop 实现图 D04
  accDescr: 原 Work 与 installed identity 校验后运行 Worker,Main 验证真实 committed artifacts。
  participant Agent as Agent 原 pending Work
  participant Main as Main delivery
  participant Auth as installed capability 检查
  participant Journal as PluginHost 调用链
  participant Worker as MCP Worker
  participant Lease as Main PluginCallLease
  participant Registry as ArtifactRegistry
  Main->>Agent: 查询原 pending request
  Agent-->>Main: 精确 work/package/tool binding
  Main->>Journal: settle 原调用
  Journal->>Auth: 检查 identity / request / executor / task
  Note over Auth,Worker: 无通用逐次执行确认;目录/电脑/连接等资源另行授权
  Main->>Agent: dispatch 前重查同一 pending wait
  Journal->>Worker: invokeTool(manifest contract)
  Worker->>Lease: artifacts.create / artifacts.commit
  Lease->>Registry: 注册当前调用产物
  Registry-->>Lease: Main 已提交 artifact refs
  Worker-->>Journal: structuredContent + artifacts
  Journal->>Lease: committedArtifacts()
  alt declaration / returned / committed IDs 一致
    Journal-->>Main: succeeded result
  else 校验失败或派发后结果不确定
    Journal-->>Main: failed 或 unknown(依 effect / executionState)
  end
  Main->>Agent: 原调用 receipt settlement

图中的 PluginHost 调用链参与者压缩了 Journal 与 runtime 验证步骤,不表示验证函数定义在 journal 类中。实际 plugin-runtime.ts 完成条件产物校验:produced 必须完整列举当前调用全部 committed IDs;非 produced 要求零产物;outputKey/version/声明 schema 也必须一致。派发后的非 read effect 若无法证明 completed,代码可能返回 unknown,不能简化为“报错即无副作用”。

证据:原 wait 绑定与派发前重查;真实执行与结果/unknown 分类;产物创建提交;Main committedArtifacts;条件产物语义。

D05 本地写入结果与回执交付:恢复不等于再次写盘

以下刻画 coordinator 的可证实控制流;executor 内部恢复状态没有在图中虚构成 enum。

Desktop 实现图 D05

图形正在加载;下方源代码始终可读。

Mermaid 源代码
sequenceDiagram
  accTitle: Desktop 实现图 D05
  accDescr: 恢复原 Operation 的结果和回执,不把重送回执等同重复写盘。
  participant UI as Main 恢复入口
  participant Coord as LocalFileV4Coordinator
  participant API as Agent pending / receipts
  participant Exec as LocalFileV4Executor
  participant Local as 本地结果与写入事实
  participant Diag as 安全诊断
  UI->>Coord: recoverPending(run/invocation/session)
  Coord->>API: queryPending
  API-->>Coord: 原 operation deliveries
  Coord->>Exec: executeDelivery(原 operation + digest + scope)
  Exec->>Local: 按原 operation 解析执行/恢复事实
  alt 可提供原 receipt body
    Exec-->>Coord: response + responseDigest
    Coord->>API: submitReceipt(同 operationId/requestDigest)
    alt Agent 接受
      API-->>Coord: ACK
      Coord->>Exec: markWriteReceiptDelivered
    else 永久拒绝或交付失败
      Coord->>Exec: 永久拒绝时记 rejection
      Coord->>Diag: 未确认;保留原 operation 身份
    end
  else LocalFileV4ReceiptUnavailableError
    Exec-->>Coord: 原 receipt metadata
    Coord->>API: reconcileReceipt(original)
  end

这里 fs/change 不走 read-unavailable 的降级路径。重送原 receipt 与重新执行文件 mutation 必须分开;不能从网络失败推断“没有写入”。只有完成 settlement 后 coordinator 才 releaseOperation;失败通知用安全错误码,不把任意文件错误或 receipt body 写日志。恢复期间仍计入 update-blocking activity。

证据:恢复与更新阻塞计数;提交 receipt / 标记 delivered / 拒绝;原 metadata 对账与未确认处理。

D06 自动安装策略:ready 与 installed 分开

此为概念策略图,不是 UpdateState enum 的完整转换图。

Desktop 实现图 D06

图形正在加载;下方源代码始终可读。

Mermaid 源代码
flowchart TD
  accTitle: Desktop 实现图 D06
  accDescr: 启动和空闲安装分别检查待安装状态、工作活动、静默时间及尝试次数。
  Start["启动读取 updater snapshot"]
  Pending{"启动时已有 ready + pendingRestart?"}
  BG["正常工作台;后台 check / download"]
  Gate{"安装条件满足?"}
  Block["阻止新 IPC;复查 busy / idle"]
  Reserve["持久记录本版本尝试次数;再复查"]
  Apply["调用 updater apply"]
  Hold["保留待安装;不中断现有工作"]
  Start --> Pending
  Pending -->|"否"| BG
  Pending -->|"是"| Gate
  BG -->|"idle-install 默认关闭;开启后轮询"| Gate
  Gate -->|"无 busy;自动次数未超限;idle 分支另验时间"| Block
  Gate -->|"不满足 / 读取失败"| Hold
  Block -->|"通过"| Reserve
  Block -->|"条件变化"| Hold
  Reserve -->|"通过"| Apply
  Reserve -->|"条件变化;回退预留计数"| Hold
  Apply -->|"失败;解除 admission block"| Hold

启动只为启动前已下载的待安装更新等待;新下载不阻塞正常启动。Idle 分支要求系统 idle/locked ≥10 分钟、工作静默和 resume 静默 ≥60 秒、无阻塞活动;每 30 秒检查。自动尝试每版本最多 3 次(显式 retry 另处理)。不会通过取消任务来制造 idle。安装是否成功由 updater/下次启动确认,图没有虚构 apply → installed。

证据:阈值与默认值;启动及 idle 判定;阻止新工作、预留次数、复核及失败。

D07 UML:提交协调器、Store 与传输接口

这是实际类与接口的 UML 局部结构图,不是把所有名词都当类。Delivery 通过构造参数持有 Store,并由工厂取得 RuntimeWorkBoundTransport 接口;它没有实现或继承该接口。连线只表达关联/依赖,不使用无源码依据的组合菱形。

Desktop 提交协调器的 UML 依赖

图形正在加载;下方源代码始终可读。

Mermaid 源代码
classDiagram
  accTitle: Desktop 提交协调器的 UML 依赖
  accDescr: RuntimeWorkDelivery 使用 Store 与按 scope 取得的 BoundTransport,Store 管理命令状态,传输接口提供发送和只读查询。
  class RuntimeWorkDelivery {
    +submit(request) Promise
    +stop(input) Promise
    +resumePreparedStop(request) Promise
    +reconcileUnknownStop(request) Promise
  }
  class RuntimeWorkDeliveryStore {
    +prepare(request) Promise
    +prepareStop(stop) Promise
    +bindStopTarget(stop, target) Promise
    +beginSending(request) Promise
    +recover(scopeDigest) Promise
    +acknowledgeStop(request, ack) Promise
  }
  class RuntimeWorkBoundTransport {
    <<interface>>
    +assertCurrent() Promise
    +send(request) Promise
    +sendStop(request) Promise
    +queryStop(request) Promise
    +query(request) Promise
    +view(binding) Promise
  }
  RuntimeWorkDelivery --> RuntimeWorkDeliveryStore : options.store
  RuntimeWorkDelivery ..> RuntimeWorkBoundTransport : transportForScope 返回

成员签名为阅读而简写,queryStop 在实际接口中可选。请求/记录等 TypeScript 类型没有被画成额外运行实例。Store 的内存状态推进与磁盘耐久性也不能等同:当前版本的加密持久发布是异步 best-effort,失败只告警,不落明文。

证据:传输接口及协调器注入;Store 类及持久性边界;Stop 的建立与一次绑定;ACK 与首次发送屏障。

D08 Stop 时序:先绑定原目标,unknown 只核对

此图补足 D02 的 Stop 专用路径,不重画 submission 状态机。为突出分支,图中 Transport 聚合了接口调用及其服务端响应,不表示它是另一个状态权威。

Stop 目标绑定与未知结果核对时序

图形正在加载;下方源代码始终可读。

Mermaid 源代码
sequenceDiagram
  accTitle: Stop 目标绑定与未知结果核对时序
  accDescr: Stop 先记录原来源,解析原 Root 后仅一次发送;不确定结果只查原 Stop ACK,不创建替代命令。
  participant Caller as Main 调用方
  participant D as RuntimeWorkDelivery
  participant S as DeliveryStore
  participant T as BoundTransport / Agent
  Caller->>D: stop(commandId, sourceRef, submission 或 resolved)
  D->>S: prepareStop(原身份与来源)
  S-->>D: unresolved 或既有记录
  Note over D,S: 非 unresolved / prepared 直接返回既有记录
  D->>T: assertCurrent
  opt unresolved 且没有已知 binding
    D->>T: query(原 submission)
    T-->>D: 原提交结果
    D->>T: assertCurrent;验证 binding
  end
  alt unresolved 且无 binding 或不是 root_run
    D-->>Caller: 保持 unresolved,不发送
  else 已取得原 Root 或已有 prepared 目标
    opt 尚未绑定
      D->>S: bindStopTarget(原 rootRunId,冻结 body)
    end
    D->>S: beginSending(只允许 prepared)
    D->>T: assertCurrent;sendStop(原冻结命令)
    alt ACK 可确认
      T-->>D: 原 Stop ACK
      D->>T: assertCurrent
      D->>S: acknowledgeStop
    else 发送或 ACK 保存出现异常
      D->>S: recover(sending 转 unknown)
      D-->>Caller: 抛出异常,不重发
    end
  end
  Caller->>D: 稍后 reconcileUnknownStop(原命令)
  D->>S: recover + prepare,读取原记录
  opt 记录为 unknown 且 queryStop 可用
    D->>T: assertCurrent;queryStop(原冻结 Stop)
    T-->>D: ACK 或 null
    D->>T: assertCurrent
    alt 有 ACK
      D->>S: acknowledgeStop
    else null
      D-->>Caller: 保持原 unknown
    end
  end

仅 prepared 且从未跨过发送屏障的 Stop 可走 resumePreparedStop。身份校验失败、目标冲突均中止操作;图省略其异常箭头。ACK 表示控制屏障已接受,不表示已经撤销物理副作用。Store 的磁盘 best-effort 边界见 D07,不能把图中方法返回解释成强耐久落盘证明。

证据:Stop 来源解析与目标绑定;prepared 恢复与 unknown 只读核对;冻结目标校验与单次发送;recover 与 ACK 语义;ACK 控制屏障而非回滚。

D09 文件时序:artifact 引用物化为调用内只读副本

D04 讲产物创建与结算;这里追踪已有产物作为输入的 files.materialize 分支。verifyArtifactInput 是函数参与者,不是独立服务;原产物与调用目录副本必须分清。

Plugin artifact 输入物化时序

图形正在加载;下方源代码始终可读。

Mermaid 源代码
sequenceDiagram
  accTitle: Plugin artifact 输入物化时序
  accDescr: Main 核验调用 token、capability、原参数引用与作用域后读取 artifact 字节,在独立调用目录写只读副本并返回路径;finish 清理调用目录。
  participant W as Plugin 调用进程
  participant L as Main PluginCallLease
  participant V as verifyArtifactInput 函数
  participant F as 本机文件系统
  W->>L: files.materialize(callId、token、artifact 引用)
  L->>L: 解析 HostRequest;核验 active、callId、token
  L->>L: file-input capability;引用必须来自原 args
  alt artifactId 或 session / conversation / run 缺失
    L-->>W: PLUGIN_FILE_DENIED
  else 引用具备原作用域
    L->>V: registry、artifactId、scope、100 MiB 上限、readBytes
    alt 核验失败或没有字节
      V-->>L: 错误或无 bytes
      L-->>W: PLUGIN_FILE_DENIED
    else 返回已验证字节
      V-->>L: bytes 与 displayName
      L->>L: assertActive;限制扩展名,生成随机 input 路径
      L->>F: 调用目录内 writeFile(wx,0400)
      alt 写入失败
        L-->>W: PLUGIN_FILE_DENIED
      else 写入成功
        L->>L: assertActive;记录 materialized 路径
        L-->>W: 调用内 path(不是原 artifact 路径)
      end
    end
  end
  Note over L,F: lease.finish 时 abort、撤销调用资源,并 rm 调用目录

每个 lease 的目录使用独立随机文件系统身份;复制后再次核验 active,防止撤销中的结果继续发布。0400 是文件权限,不是 OS sandbox,也不代表任意已安装进程没有其他用户级权限。此图仅覆盖 artifact 引用分支,不把 selected-file 授权流程或产物输出混入同一链路。

证据:独立调用目录与原 args 引用集合;调用凭证校验;artifact 输入核验与副本写入;finish 撤销与目录清理。

本次快照新增与非基线内容

  • 条件产物:以上第 4 图对应 pin 8eecd12081dbb5c725c1be3754dfaae7b845aa31 之后的新 Host 核验。Report 四个合同场景已回默认 System,但仅证明 Desktop 自有冻结 fixture 路径,不等于所有官方包验收。Report 门禁与专用 producer 限制。
  • 轨迹采集:由 Main 的 developer + panelVisible 偏好控制,新提交前最多等待 2 秒诊断 ready handshake;身份/设置失效撤销本地采集。不是额外的 Run authority,也没有独立的 start-capture 按钮/IPC。设置、2 秒界限、invalidate。
  • 发布渠道不是本基线:GitHub PR #4 是 draft,head 2eb1d524a9c9050c81beb8f77c38174f471ac3a7;stable/beta/preview 的安装/配置/feed 隔离不可放进 master 实现图。当前图只描述 master 更新协调与安装策略。

机制说明

Desktop:进程边界与本机能力

沿 Main 边界阅读本机能力

Desktop session 表达 Main 持有的本机执行上下文,Server session 表达 Agent 会话;跨边界时需要明确配对。本机 PluginHost 管插件投影和回执。普通文件操作属 Local File V4 架构族(Desktop 协议 v3 起不再有独立的 Local File wire 版本,path-free 不变):账本在 Agent,执行与附件组装在 Main;Renderer 只提交无路径的草稿意图。

这些宿主共同位于本机责任范围,不意味着它们共享同一状态机。chat 提交与观察统一走 Work 路径(register-runtime-v2-ipc 已删除);runtime-v2.1 入口不再放行(见下表 RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED)。

Gateway 协议硬门族(426 / fail-closed)

钉点 Agent e2adc9a3c325 / Desktop 8eecd12081db 起,Desktop↔Agent 只剩一个协议版本 DESKTOP_PROTOCOL_VERSION = 3(Agent ADR-0090 D4、Desktop ADR-0087 D3:版本即能力,不再协商 feature token),所有 Desktop 准入边界对非 3 的版本统一返回 426 DESKTOP_UPGRADE_REQUIRED(chat 受理按 ADR-0093 只在声明了本机执行协议或携带本机执行载荷时检查,见下表),body { code, message: "请升级 AidaWork 客户端。", expectedProtocolVersion: 3 },Desktop 映射到升级提示、不做容错解码。原 desktop_protocol_version_required、local_execution_recovery_protocol_upgrade_required、LOCAL_FILE_PROTOCOL_UPGRADE_REQUIRED 三个码已删除。Interaction Kernel 与 Runtime Work 的协议门是另外两扇门,不要合并理解。

错误码 / 信号 入口 判定 阻断范围
DESKTOP_UPGRADE_REQUIRED chat POST /(头 X-AIDA-Protocol 有值且 ≠ 3;或没带头却携带本机执行载荷 localExecutor / localFilesV4 / assembleSubmittedLocalFileAttachments / pluginTask / pluginTools / userSkill;均审计 desktop_protocol_version_rejected);chat POST / /validate-local-executor / 路由预览的 localExecutor.version;本机执行回执、Local File 回执与投递、durable recovery GET /pending(头 Aida-Local-Execution-Protocol-Version)、桌面分发 版本 ≠ 3;载荷缺 version 按 schema 违规(不算升级信号) 整次 chat 提交 / 该端点
RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED chat POST 按提交 wire + policy 校验;取消提交、api-runs cancel、active-run 分别有独立门(见协议地图) 非支持的提交 wire;skill-v2 与 policy 不匹配另有码 该 Runtime/Run 路径
interaction_protocol_upgrade_required api-conversation-interactions 全路由中间件 头 Aida-Interaction-Protocol-Version 未接受(Kernel 现为协议 2) 该对话 Interaction API

ADR-0093(钉点 Agent e2adc9a3c325,状态 Proposed、代码已落地):本机执行协议只约束本机执行。chat POST 没带 X-AIDA-Protocol、请求体也没有本机执行载荷(清单 LOCAL_EXECUTION_CHAT_BODY_FIELDS)时,不再 426,进入 Runtime Work 协议检查和后续受理;这只证明通过协议门,最终工具集合仍须分别核验能力与执行绑定;这是为不做本机执行的客户端(如移动端第一阶段)准备的。Desktop 始终带头 3,行为不变;本机执行回执、Local File、durable recovery、桌面分发入口仍按 ADR-0090 D4 硬切。

载荷里没有合法的 localFileCapability 不再触发 426,只是本轮不注册 Local File V4 工具(localFileV4Admitted)。Desktop 侧 shared/generated/protocol-version.ts 由 Agent tool-client 生成;pending-read 恢复把 426 映射为 PENDING_LOCAL_READ_PROTOCOL_UPGRADE_REQUIRED。跨端(Desktop Electron / E2E)验收按两个 ADR 的记载尚未运行。

证据钉点:aida-agent e2adc9a3c325a258a88d68103de87e6630a3b676,aida-desktop 8eecd12081dbb5c725c1be3754dfaae7b845aa31。

证据与范围

  • aida-desktop · CONTEXT.md L1388–1418 · Dual session identity · 4346d79eb364(历史引用:该文件在上一钉点与当前钉点均不存在,未能复核;见 ATLAS-DEBT)

  • aida-desktop · apps/desktop/electron/plugin-host/plugin-host.ts L659–689 · listProjections · 4346d79eb364

  • aida-agent · docs/architecture/lifecycle-map.md L42–98 · e2adc9a3c325(历史引用:该文件在上一钉点与当前钉点均不存在,未能复核;见 ATLAS-DEBT)

  • aida-desktop · apps/desktop/electron/local-files-v4/assemble-submitted-attachments.ts L49–80 · assembleSubmittedLocalFileAttachments · 4346d79eb364

  • aida-desktop · apps/desktop/electron/agent-loop/register-runtime-work-ipc.ts L251–276 · submitSubmission · 4346d79eb364(register-runtime-v2-ipc 已删除)

  • aida-agent · packages/agent/src/runtime/work/run-work-admission.ts L16–57 · bindAdmittedWork · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L374–412 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L489–529 · chatBodyCarriesLocalExecution · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/request-schemas.ts L74–91 · LOCAL_EXECUTION_CHAT_BODY_FIELDS · e2adc9a3c325

  • aida-agent · docs/adr/0093-chat-admission-separates-runtime-and-local-execution-protocols.md L26–58 · 本机执行协议只约束本机执行 · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L381–421 · RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-conversation-interactions.ts L465–495 · interaction_protocol_upgrade_required · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-durable-local-execution-recovery.ts L66–72 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/protocol-version.ts L1–38 · DESKTOP_UPGRADE_REQUIRED · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/chat-routes.ts L520–524 · desktopPayloadVersionUnsupported · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-local-execution-receipts.ts L42–47 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-local-file-v4.ts L82–87 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-agent · packages/agent/src/gateway/api-desktop-distribution.ts L55–59 · DESKTOP_UPGRADE_REQUIRED_BODY · e2adc9a3c325

  • aida-desktop · apps/desktop/shared/generated/protocol-version.ts L1–8 · DESKTOP_PROTOCOL_VERSION · 4346d79eb364

  • aida-desktop · docs/adr/0087-local-capability-convergence-and-protocol-v3.md L30–32 · DESKTOP_PROTOCOL_VERSION = 3 · 4346d79eb364

  • aida-agent · packages/tool-client/src/types/runtime-execution.ts L6–46 · RUNTIME_EXECUTION_PROTOCOL · e2adc9a3c325

结论来自固定版本的静态源码与合同阅读;实现存在、默认开关和生产启用分别判断。本站代码证据面板列出声明状态与具体限制。

远程 Desktop 设备目录(钉点 e2adc9a3c325 / 8eecd12081db)

  • 迁移 188 + DesktopExecutionDirectory:登记 desktop_execution_devices、online lease、continuation_context.remoteDesktop。
  • chat 可带 executionTarget / remote binding;无头本机载荷规则仍受 ADR-0093 约束。
  • 真机远程登记、租赁续期、跨设备执行 未核实。视图 remote-device。

Mermaid 实现图册

九张 Desktop 图:信任边界、持久提交 unknown、executor 租约、Plugin 条件产物、本机回执恢复、更新安装策略、Delivery UML、Stop 核对时序、artifact 输入物化时序。与服务端九张图对照;具体枚举与概念流程已分别标明。

Runtime 提交 wire 与原 Work identity

chat POST 的 Runtime 提交门接受缺省/空值(无 policy)、runtime-work-v1(无 policy),以及 runtime-work-skill-v2 且携带合法 skillExecutionPolicy;其他非空头为 RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED,头与 policy 不匹配为 RUNTIME_WORK_SKILL_POLICY_MISMATCH,均返回 426。原 Work binding 仍是 runtime-work-v1;取消提交、补充材料等路由单独判定,见协议地图。

证据:提交门 与 实际 chat POST 调用。

Desktop 实现图谱(固定代码快照)

基线:4346d79eb364b502ef87c0869a494dfed7964419,Desktop 0.2.5。下列图为代码阅读的结构化表达,不代表运行验收。D02 状态图与 D08 时序图使用实际 phase 名;UML 图区分类与接口,其余图为概念结构、调用时序或策略流程,不新增协议状态。

图索引

D01 信任边界:安装信任与资源授权分开

flowchart LR
  accTitle: Desktop 实现图 D01
  accDescr: Main 与 Renderer 和执行进程的权限边界,安装信任不等于资源授权或操作系统沙箱。
  R["Renderer / preload"]
  M["Electron Main"]
  A["Agent 服务"]
  V["Main Credential Vault"]
  I["installed capability 授权"]
  P["独立资源授权"]
  W["Plugin / Skill 进程"]
  F["本地文件与产物索引"]
  R -->|"受限 IPC"| M
  M -->|"当前身份绑定的请求"| A
  V -->|"Main 专用凭据"| M
  M --> I
  I -->|"identity + request + executor 检查"| W
  M --> P
  P -->|"Computer Use / 连接授权 / 文件操作"| F
  W -->|"Host API"| M
  M -->|"opaque ID 与私有路径映射"| F

不能把此图读成沙箱:安装后的执行不再等待通用 per-call/always-allow 确认,也不由 ClientAccessMode 决定(旧 PluginExecutionApprovalGate 与 directory-batch 已随 eb0f30dc 移除);但身份、原任务、包完整性、请求摘要检查仍存在。Computer Use 窗口许可、连接授权、typed user action 和本地文件 effects 各有自己的边界。批准运行的进程拥有 OS 用户文件权限与网络,working directory 不是 OS sandbox。

证据:apps/desktop/electron/installed-capability-authorization.ts;Skill 实际 wiring;Plugin 实际 wiring。

D02 持久提交与 unknown:实际 phase 的局部状态图

以下是 submission delivery phase 的有意局部视图,不是 Run 状态机;省略 queued/reply/rejected 等 admission outcome。图中的 accepted 是服务器接受原提交,不是业务执行成功。

stateDiagram-v2
  accTitle: Desktop 实现图 D02
  accDescr: 提交阶段保存原 command,结果未知只查询原提交,不自动重放。
  [*] --> prepared: prepare 冻结原始 intent 并更新 Store
  prepared --> sending: beginSending 唯一首次发送屏障
  prepared --> withdrawn: 发送前撤回
  sending --> accepted: 原 command 的有效 ACK
  sending --> unknown: recover 发现持久 sending
  unknown --> accepted: 查询并验证原 Message/binding
  unknown --> unknown: 查询仍 unknown
  note right of unknown
    不创建替代 command
    不重新发送物理提交
    404 / not_started 不授予重发
  end note
  note right of accepted
    保留原 binding
    不降级回 sending
  end note

这里的 Store 保存不等于强耐久落盘:当前实现先推进内存,加密磁盘发布为异步 best-effort,失败只告警且不写明文;图不保证断电后记录必然存在。见 Store 持久性边界。

身份切换/摘要不符是拒绝操作,不虚构一个 phase。Stop 使用独立 command,先 unresolved,再解析并一次性绑定原 rootRunId 为 prepared;未知 Stop 仅 queryStop。由于 Stop 与 submission 的建立条件不同,不把两者折叠成同一个状态机。

证据:提交一次物理发送;recover/accept 实际转换;发送与撤回屏障;原提交查询;Stop 绑定与查询。

单次发送屏障只约束仍保有的 Store 记录,不是跨崩溃或记录丢失的 exactly-once 保证。

D03 Desktop executor:租约与 inbox,不是第二个模型循环

sequenceDiagram
  accTitle: Desktop 实现图 D03
  accDescr: Desktop 注册租约并并行续约与拉取 inbox,原 effect owner 执行。
  participant Tick as Main lifecycle tick
  participant Host as DesktopExecutionHost
  participant Auth as 当前身份 owner
  participant API as Agent executor API
  participant Work as 原 Work coordinator
  participant Effect as 原 effect owner
  Tick->>Host: tick(已有连接时不重复启动)
  Host->>Auth: owner + registration
  Host->>API: GET capabilities
  Host->>API: POST self/lease
  API-->>Host: lease(验证 deviceId)
  par 心跳续约
    Host->>API: POST self/lease
    API-->>Host: 同 deviceId / leaseId
  and inbox 接收
    Host->>API: GET self/inbox(leaseId / revision / after)
    API-->>Host: 分页 items + ETag
    Host->>Work: accept(items, scopeDigest)
    Work->>Effect: 复用既有执行 owner
  end
  alt 身份变化
    Auth-->>Host: invalidate
    Host->>Host: generation++ / abort / clear
  else 连接故障
    Host->>Host: clear + 有界退避
    Note over Host,API: 不在普通网络失败时 DELETE,避免迟到删除误伤新租约
  end

心跳与接收并行,任一路失败会结束本连接;正常 close 才 best-effort 删除已捕获 lease。inbox 只是连接交付,不创造新的模型或 effect ledger。

证据:连接生命周期;注册/并行心跳/分页 inbox/释放。

D04 Plugin 条件产物:Worker 声明不能代替 Main 事实

sequenceDiagram
  accTitle: Desktop 实现图 D04
  accDescr: 原 Work 与 installed identity 校验后运行 Worker,Main 验证真实 committed artifacts。
  participant Agent as Agent 原 pending Work
  participant Main as Main delivery
  participant Auth as installed capability 检查
  participant Journal as PluginHost 调用链
  participant Worker as MCP Worker
  participant Lease as Main PluginCallLease
  participant Registry as ArtifactRegistry
  Main->>Agent: 查询原 pending request
  Agent-->>Main: 精确 work/package/tool binding
  Main->>Journal: settle 原调用
  Journal->>Auth: 检查 identity / request / executor / task
  Note over Auth,Worker: 无通用逐次执行确认;目录/电脑/连接等资源另行授权
  Main->>Agent: dispatch 前重查同一 pending wait
  Journal->>Worker: invokeTool(manifest contract)
  Worker->>Lease: artifacts.create / artifacts.commit
  Lease->>Registry: 注册当前调用产物
  Registry-->>Lease: Main 已提交 artifact refs
  Worker-->>Journal: structuredContent + artifacts
  Journal->>Lease: committedArtifacts()
  alt declaration / returned / committed IDs 一致
    Journal-->>Main: succeeded result
  else 校验失败或派发后结果不确定
    Journal-->>Main: failed 或 unknown(依 effect / executionState)
  end
  Main->>Agent: 原调用 receipt settlement

图中的 PluginHost 调用链参与者压缩了 Journal 与 runtime 验证步骤,不表示验证函数定义在 journal 类中。实际 plugin-runtime.ts 完成条件产物校验:produced 必须完整列举当前调用全部 committed IDs;非 produced 要求零产物;outputKey/version/声明 schema 也必须一致。派发后的非 read effect 若无法证明 completed,代码可能返回 unknown,不能简化为“报错即无副作用”。

证据:原 wait 绑定与派发前重查;真实执行与结果/unknown 分类;产物创建提交;Main committedArtifacts;条件产物语义。

D05 本地写入结果与回执交付:恢复不等于再次写盘

以下刻画 coordinator 的可证实控制流;executor 内部恢复状态没有在图中虚构成 enum。

sequenceDiagram
  accTitle: Desktop 实现图 D05
  accDescr: 恢复原 Operation 的结果和回执,不把重送回执等同重复写盘。
  participant UI as Main 恢复入口
  participant Coord as LocalFileV4Coordinator
  participant API as Agent pending / receipts
  participant Exec as LocalFileV4Executor
  participant Local as 本地结果与写入事实
  participant Diag as 安全诊断
  UI->>Coord: recoverPending(run/invocation/session)
  Coord->>API: queryPending
  API-->>Coord: 原 operation deliveries
  Coord->>Exec: executeDelivery(原 operation + digest + scope)
  Exec->>Local: 按原 operation 解析执行/恢复事实
  alt 可提供原 receipt body
    Exec-->>Coord: response + responseDigest
    Coord->>API: submitReceipt(同 operationId/requestDigest)
    alt Agent 接受
      API-->>Coord: ACK
      Coord->>Exec: markWriteReceiptDelivered
    else 永久拒绝或交付失败
      Coord->>Exec: 永久拒绝时记 rejection
      Coord->>Diag: 未确认;保留原 operation 身份
    end
  else LocalFileV4ReceiptUnavailableError
    Exec-->>Coord: 原 receipt metadata
    Coord->>API: reconcileReceipt(original)
  end

这里 fs/change 不走 read-unavailable 的降级路径。重送原 receipt 与重新执行文件 mutation 必须分开;不能从网络失败推断“没有写入”。只有完成 settlement 后 coordinator 才 releaseOperation;失败通知用安全错误码,不把任意文件错误或 receipt body 写日志。恢复期间仍计入 update-blocking activity。

证据:恢复与更新阻塞计数;提交 receipt / 标记 delivered / 拒绝;原 metadata 对账与未确认处理。

D06 自动安装策略:ready 与 installed 分开

此为概念策略图,不是 UpdateState enum 的完整转换图。

flowchart TD
  accTitle: Desktop 实现图 D06
  accDescr: 启动和空闲安装分别检查待安装状态、工作活动、静默时间及尝试次数。
  Start["启动读取 updater snapshot"]
  Pending{"启动时已有 ready + pendingRestart?"}
  BG["正常工作台;后台 check / download"]
  Gate{"安装条件满足?"}
  Block["阻止新 IPC;复查 busy / idle"]
  Reserve["持久记录本版本尝试次数;再复查"]
  Apply["调用 updater apply"]
  Hold["保留待安装;不中断现有工作"]
  Start --> Pending
  Pending -->|"否"| BG
  Pending -->|"是"| Gate
  BG -->|"idle-install 默认关闭;开启后轮询"| Gate
  Gate -->|"无 busy;自动次数未超限;idle 分支另验时间"| Block
  Gate -->|"不满足 / 读取失败"| Hold
  Block -->|"通过"| Reserve
  Block -->|"条件变化"| Hold
  Reserve -->|"通过"| Apply
  Reserve -->|"条件变化;回退预留计数"| Hold
  Apply -->|"失败;解除 admission block"| Hold

启动只为启动前已下载的待安装更新等待;新下载不阻塞正常启动。Idle 分支要求系统 idle/locked ≥10 分钟、工作静默和 resume 静默 ≥60 秒、无阻塞活动;每 30 秒检查。自动尝试每版本最多 3 次(显式 retry 另处理)。不会通过取消任务来制造 idle。安装是否成功由 updater/下次启动确认,图没有虚构 apply → installed。

证据:阈值与默认值;启动及 idle 判定;阻止新工作、预留次数、复核及失败。

D07 UML:提交协调器、Store 与传输接口

这是实际类与接口的 UML 局部结构图,不是把所有名词都当类。Delivery 通过构造参数持有 Store,并由工厂取得 RuntimeWorkBoundTransport 接口;它没有实现或继承该接口。连线只表达关联/依赖,不使用无源码依据的组合菱形。

classDiagram
  accTitle: Desktop 提交协调器的 UML 依赖
  accDescr: RuntimeWorkDelivery 使用 Store 与按 scope 取得的 BoundTransport,Store 管理命令状态,传输接口提供发送和只读查询。
  class RuntimeWorkDelivery {
    +submit(request) Promise
    +stop(input) Promise
    +resumePreparedStop(request) Promise
    +reconcileUnknownStop(request) Promise
  }
  class RuntimeWorkDeliveryStore {
    +prepare(request) Promise
    +prepareStop(stop) Promise
    +bindStopTarget(stop, target) Promise
    +beginSending(request) Promise
    +recover(scopeDigest) Promise
    +acknowledgeStop(request, ack) Promise
  }
  class RuntimeWorkBoundTransport {
    <<interface>>
    +assertCurrent() Promise
    +send(request) Promise
    +sendStop(request) Promise
    +queryStop(request) Promise
    +query(request) Promise
    +view(binding) Promise
  }
  RuntimeWorkDelivery --> RuntimeWorkDeliveryStore : options.store
  RuntimeWorkDelivery ..> RuntimeWorkBoundTransport : transportForScope 返回

成员签名为阅读而简写,queryStop 在实际接口中可选。请求/记录等 TypeScript 类型没有被画成额外运行实例。Store 的内存状态推进与磁盘耐久性也不能等同:当前版本的加密持久发布是异步 best-effort,失败只告警,不落明文。

证据:传输接口及协调器注入;Store 类及持久性边界;Stop 的建立与一次绑定;ACK 与首次发送屏障。

D08 Stop 时序:先绑定原目标,unknown 只核对

此图补足 D02 的 Stop 专用路径,不重画 submission 状态机。为突出分支,图中 Transport 聚合了接口调用及其服务端响应,不表示它是另一个状态权威。

sequenceDiagram
  accTitle: Stop 目标绑定与未知结果核对时序
  accDescr: Stop 先记录原来源,解析原 Root 后仅一次发送;不确定结果只查原 Stop ACK,不创建替代命令。
  participant Caller as Main 调用方
  participant D as RuntimeWorkDelivery
  participant S as DeliveryStore
  participant T as BoundTransport / Agent
  Caller->>D: stop(commandId, sourceRef, submission 或 resolved)
  D->>S: prepareStop(原身份与来源)
  S-->>D: unresolved 或既有记录
  Note over D,S: 非 unresolved / prepared 直接返回既有记录
  D->>T: assertCurrent
  opt unresolved 且没有已知 binding
    D->>T: query(原 submission)
    T-->>D: 原提交结果
    D->>T: assertCurrent;验证 binding
  end
  alt unresolved 且无 binding 或不是 root_run
    D-->>Caller: 保持 unresolved,不发送
  else 已取得原 Root 或已有 prepared 目标
    opt 尚未绑定
      D->>S: bindStopTarget(原 rootRunId,冻结 body)
    end
    D->>S: beginSending(只允许 prepared)
    D->>T: assertCurrent;sendStop(原冻结命令)
    alt ACK 可确认
      T-->>D: 原 Stop ACK
      D->>T: assertCurrent
      D->>S: acknowledgeStop
    else 发送或 ACK 保存出现异常
      D->>S: recover(sending 转 unknown)
      D-->>Caller: 抛出异常,不重发
    end
  end
  Caller->>D: 稍后 reconcileUnknownStop(原命令)
  D->>S: recover + prepare,读取原记录
  opt 记录为 unknown 且 queryStop 可用
    D->>T: assertCurrent;queryStop(原冻结 Stop)
    T-->>D: ACK 或 null
    D->>T: assertCurrent
    alt 有 ACK
      D->>S: acknowledgeStop
    else null
      D-->>Caller: 保持原 unknown
    end
  end

仅 prepared 且从未跨过发送屏障的 Stop 可走 resumePreparedStop。身份校验失败、目标冲突均中止操作;图省略其异常箭头。ACK 表示控制屏障已接受,不表示已经撤销物理副作用。Store 的磁盘 best-effort 边界见 D07,不能把图中方法返回解释成强耐久落盘证明。

证据:Stop 来源解析与目标绑定;prepared 恢复与 unknown 只读核对;冻结目标校验与单次发送;recover 与 ACK 语义;ACK 控制屏障而非回滚。

D09 文件时序:artifact 引用物化为调用内只读副本

D04 讲产物创建与结算;这里追踪已有产物作为输入的 files.materialize 分支。verifyArtifactInput 是函数参与者,不是独立服务;原产物与调用目录副本必须分清。

sequenceDiagram
  accTitle: Plugin artifact 输入物化时序
  accDescr: Main 核验调用 token、capability、原参数引用与作用域后读取 artifact 字节,在独立调用目录写只读副本并返回路径;finish 清理调用目录。
  participant W as Plugin 调用进程
  participant L as Main PluginCallLease
  participant V as verifyArtifactInput 函数
  participant F as 本机文件系统
  W->>L: files.materialize(callId、token、artifact 引用)
  L->>L: 解析 HostRequest;核验 active、callId、token
  L->>L: file-input capability;引用必须来自原 args
  alt artifactId 或 session / conversation / run 缺失
    L-->>W: PLUGIN_FILE_DENIED
  else 引用具备原作用域
    L->>V: registry、artifactId、scope、100 MiB 上限、readBytes
    alt 核验失败或没有字节
      V-->>L: 错误或无 bytes
      L-->>W: PLUGIN_FILE_DENIED
    else 返回已验证字节
      V-->>L: bytes 与 displayName
      L->>L: assertActive;限制扩展名,生成随机 input 路径
      L->>F: 调用目录内 writeFile(wx,0400)
      alt 写入失败
        L-->>W: PLUGIN_FILE_DENIED
      else 写入成功
        L->>L: assertActive;记录 materialized 路径
        L-->>W: 调用内 path(不是原 artifact 路径)
      end
    end
  end
  Note over L,F: lease.finish 时 abort、撤销调用资源,并 rm 调用目录

每个 lease 的目录使用独立随机文件系统身份;复制后再次核验 active,防止撤销中的结果继续发布。0400 是文件权限,不是 OS sandbox,也不代表任意已安装进程没有其他用户级权限。此图仅覆盖 artifact 引用分支,不把 selected-file 授权流程或产物输出混入同一链路。

证据:独立调用目录与原 args 引用集合;调用凭证校验;artifact 输入核验与副本写入;finish 撤销与目录清理。

本次快照新增与非基线内容

  • 条件产物:以上第 4 图对应 pin 8eecd12081dbb5c725c1be3754dfaae7b845aa31 之后的新 Host 核验。Report 四个合同场景已回默认 System,但仅证明 Desktop 自有冻结 fixture 路径,不等于所有官方包验收。Report 门禁与专用 producer 限制。
  • 轨迹采集:由 Main 的 developer + panelVisible 偏好控制,新提交前最多等待 2 秒诊断 ready handshake;身份/设置失效撤销本地采集。不是额外的 Run authority,也没有独立的 start-capture 按钮/IPC。设置、2 秒界限、invalidate。
  • 发布渠道不是本基线:GitHub PR #4 是 draft,head 2eb1d524a9c9050c81beb8f77c38174f471ac3a7;stable/beta/preview 的安装/配置/feed 隔离不可放进 master 实现图。当前图只描述 master 更新协调与安装策略。

代码证据

引用核验检查固定 commit 的文件与范围;实现结论来自代码阅读。自动检查不证明生产环境已启用。

已核验实现

Desktop session 与 Server session 明确配对,不能互换授权。

aida-desktopGLOSSARY.md:1361–13674346d79eb36402355e51118df0edf1f98586880c符号:Dual session identity
已核验实现

PluginHost 在 Main 内管理投影和回执;普通文件操作属 Local File V4 架构族(Protocol v3 下不再有独立的 Local File wire 版本号):账本在 Agent,本机执行与附件组装在 Main。

aida-desktopapps/desktop/electron/plugin-host/plugin-host.ts:934–9644346d79eb36402355e51118df0edf1f98586880c符号:listProjections
aida-agentpackages/agent/src/shared/interaction-kernel-state.ts:11–417f2e519936b57902d4907ed8026fe1ecdd146e82符号:INTERACTION_STATUSES
aida-desktopapps/desktop/electron/local-files-v4/capability.ts:12–194346d79eb36402355e51118df0edf1f98586880c符号:assembleLocalFileV4Capability
已核验实现

Main 不再有独立的文本 V2 启动/观察路径(register-runtime-v2-ipc 已删除);提交与观察统一为 RuntimeWorkIpcCoordinator 一条 Work 路径。

aida-desktopapps/desktop/electron/agent-loop/register-runtime-work-ipc.ts:485–5104346d79eb36402355e51118df0edf1f98586880c符号:submitSubmission
aida-agentpackages/agent/src/runtime/work/run-work-admission.ts:30–717f2e519936b57902d4907ed8026fe1ecdd146e82符号:bindAdmittedWork
已核验实现

Gateway 426 硬门族:chat POST 头 X-AIDA-Protocol 有值且不等于 3,或没带头却携带本机执行载荷,返回 DESKTOP_UPGRADE_REQUIRED(旧 desktop_protocol_version_required 已删;ADR-0093 起无头且无本机载荷的请求不再 426);chat POST 的 Runtime 提交门接受缺省/空值(无 policy)、runtime-work-v1(无 policy),以及 runtime-work-skill-v2 且携带合法 skillExecutionPolicy;其他非空头为 RUNTIME_EXECUTION_PROTOCOL_UNSUPPORTED,头与 policy 不匹配为 RUNTIME_WORK_SKILL_POLICY_MISMATCH,均返回 426。原 Work binding 仍是 runtime-work-v1;取消提交、补充材料等路由单独判定,见协议地图。

aida-agentpackages/agent/src/gateway/chat-routes.ts:326–3647f2e519936b57902d4907ed8026fe1ecdd146e82符号:DESKTOP_UPGRADE_REQUIRED_BODY
aida-agentpackages/tool-client/src/types/runtime-work-identity.ts:4–137f2e519936b57902d4907ed8026fe1ecdd146e82符号:RUNTIME_WORK_PROTOCOL
aida-agentpackages/agent/src/gateway/request-schemas.ts:93–1107f2e519936b57902d4907ed8026fe1ecdd146e82符号:LOCAL_EXECUTION_CHAT_BODY_FIELDS
aida-agentpackages/agent/src/gateway/chat-work-admission.ts:15–247f2e519936b57902d4907ed8026fe1ecdd146e82符号:runtimeWorkSubmissionProtocol
aida-agentpackages/agent/src/gateway/chat-routes.ts:531–5357f2e519936b57902d4907ed8026fe1ecdd146e82符号:submissionProtocol
已核验实现

Interaction API 中间件在 Aida-Interaction-Protocol-Version 不被接受时返回 426 interaction_protocol_upgrade_required;Local Execution Recovery GET /pending 的版本头现与 DESKTOP_PROTOCOL_VERSION(3)绑定,不匹配返回 426 DESKTOP_UPGRADE_REQUIRED。

aida-agentpackages/agent/src/gateway/api-conversation-interactions.ts:369–3997f2e519936b57902d4907ed8026fe1ecdd146e82符号:interaction_protocol_upgrade_required
aida-agentpackages/agent/src/gateway/api-durable-local-execution-recovery.ts:78–847f2e519936b57902d4907ed8026fe1ecdd146e82符号:DESKTOP_UPGRADE_REQUIRED_BODY
aida-agentpackages/agent/src/shared/durable-local-execution.ts:20–267f2e519936b57902d4907ed8026fe1ecdd146e82符号:LOCAL_EXECUTION_RECOVERY_PROTOCOL_VERSION
已核验实现

Desktop 侧 shared/generated/protocol-version.ts 由 Agent tool-client 生成(DESKTOP_PROTOCOL_VERSION=3),ADR-0087 D3 规定版本 3 蕴含全部旧 feature token、服务端对非 3 版本返回 426 DESKTOP_UPGRADE_REQUIRED、Desktop 映射到升级提示且不做容错解码;pending-read 恢复客户端把 426 映射为 PENDING_LOCAL_READ_PROTOCOL_UPGRADE_REQUIRED。

升级提示的具体 UI 渲染路径未逐条核对;未运行 Desktop Electron / E2E。

aida-desktopapps/desktop/shared/generated/protocol-version.ts:1–84346d79eb36402355e51118df0edf1f98586880c符号:DESKTOP_PROTOCOL_VERSION
aida-desktopdocs/adr/0087-local-capability-convergence-and-protocol-v3.md:30–324346d79eb36402355e51118df0edf1f98586880c符号:DESKTOP_PROTOCOL_VERSION = 3
aida-desktopapps/desktop/electron/auth/aida-api-client.ts:2299–23044346d79eb36402355e51118df0edf1f98586880c符号:PENDING_LOCAL_READ_PROTOCOL_UPGRADE_REQUIRED
条件路径

DesktopExecutionDirectory 登记 desktop_execution_devices 与 online lease;continuation_context.remoteDesktop 绑定远程执行目标。真机远程验收未核。

未在真机跑远程登记/租赁/跨设备执行。

aida-agentpackages/agent/src/runtime/local/desktop-execution-directory.ts:107–1347f2e519936b57902d4907ed8026fe1ecdd146e82符号:DesktopExecutionDirectory
aida-agentpackages/agent/src/runtime/local/desktop-execution-directory.ts:269–2977f2e519936b57902d4907ed8026fe1ecdd146e82符号:desktop_device_registered
aida-agentpackages/agent/migrations/188_desktop_execution_devices.sql:1–307f2e519936b57902d4907ed8026fe1ecdd146e82符号:desktop_execution_devices
已核验实现

Mermaid D01 信任边界:安装信任与资源授权分开:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/installed-capability-authorization.ts:39–974346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/main.ts:1660–17004346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/main.ts:2676–27154346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D02 持久提交与 unknown:实际 phase 的局部状态图:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:59–704346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery.ts:75–1194346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:154–2284346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:547–5894346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery.ts:375–4284346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery.ts:122–2744346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D03 Desktop executor:租约与 inbox,不是第二个模型循环:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/agent-loop/desktop-execution-host.ts:40–1004346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/desktop-execution-host.ts:106–2734346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D04 Plugin 条件产物:Worker 声明不能代替 Main 事实:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/agent-loop/runtime-work-skill-delivery.ts:35–1594346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/plugin-host/plugin-runtime.ts:184–3704346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/plugin-host/plugin-capabilities.ts:470–5424346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/plugin-host/plugin-capabilities.ts:625–6414346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/shared/generated/plugin-v2/semantics.mjs:168–2174346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D05 本地写入结果与回执交付:恢复不等于再次写盘:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/local-files-v4/coordinator.ts:114–1644346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/local-files-v4/coordinator.ts:275–3924346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/local-files-v4/coordinator.ts:409–4694346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D06 自动安装策略:ready 与 installed 分开:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/update/automatic-update-installation.ts:12–424346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/update/automatic-update-installation.ts:138–2224346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/update/automatic-update-installation.ts:250–3364346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D07 UML:提交协调器、Store 与传输接口:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery.ts:22–734346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:59–1034346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:406–5134346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:515–5574346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D08 Stop 时序:先绑定原目标,unknown 只核对:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery.ts:122–2204346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery.ts:222–2744346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery.ts:277–3134346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:154–1724346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/agent-loop/runtime-work-delivery-store.ts:515–5574346d79eb36402355e51118df0edf1f98586880c
已核验实现

Mermaid D09 文件时序:artifact 引用物化为调用内只读副本:按相应源码表达责任、调用或状态;区分类、接口、依赖、合同与概念视图。

静态源码复核,不证明真实浏览器布局、所有 producer 迁移或生产部署;持久性只按实现保证。

aida-desktopapps/desktop/electron/plugin-host/plugin-capabilities.ts:216–2734346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/plugin-host/plugin-capabilities.ts:287–3204346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/plugin-host/plugin-capabilities.ts:360–4154346d79eb36402355e51118df0edf1f98586880c
aida-desktopapps/desktop/electron/plugin-host/plugin-capabilities.ts:625–6414346d79eb36402355e51118df0edf1f98586880c
已核验实现

STA-210:Desktop 有界私有异常落盘(desktop-error-journal);本机诊断,不替代服务端审计。

aida-desktopapps/desktop/electron/diagnostics/desktop-error-journal.ts:24–644346d79eb36402355e51118df0edf1f98586880c符号:DesktopErrorJournal
aida-desktopdocs/reference/desktop-error-journal.md:1–404346d79eb36402355e51118df0edf1f98586880c符号:STA-210