DeepSeek Harness Desktop 内置 Agents Anywhere 桥接包实践手册:1 个开关背后的 5 层机制
【免费下载链接】deepseek-harness-desktop为 DeepSeek Harness (DSH) 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness-desktop
DeepSeek Harness Desktop 并没有把 Agents Anywhere 当作普通的 npm 依赖来使用,而是将@agents-anywhere/dsh-bridge-next以固定版本 tarball 的形式收编进仓库,配合每 Profile 的aaEnabled开关、最小化补丁注入和一套发布前验证管线,实现「手机/平板侧 Agent 连接」能力。本文按读者视角拆解这套机制:开关在产品层面的语义、启用后 Profile 组装内部发生了什么、产物如何存放与追溯、发布管线如何生成新包、失效时系统如何失败关闭,以及把一次 AA 更新合入仓库前必须完成的验证步骤。读完你可以独立执行aa:check、aa:prepare-release、verify:profile等命令,并理解每一个字段的追溯含义。
开关 aaEnabled:用户如何控制手机连接能力
这个开关的产品语义很直接:它在设置界面呈现为「开启手机连接」(英文文案为 "Turn on phone connection"),用户打开后从侧边栏的「手机连接」入口完成后续设置。实现上,aaEnabled是存储在每个 Profile 的 Desktop 偏好里的一个字段,定义在 dsh-plugin-desktop/src/profile-preferences.ts(约 L34-L68),声明为readonly aaEnabled?: boolean,默认值为false。
几个容易被忽略的行为约束值得注意:
- 类型校验是严格的:
aaEnabled必须是 boolean(见同文件 L172 的校验逻辑); - 旧版本偏好和首次运行的选择都默认禁用;
- 用户在 Setup 向导中跳过时,系统会显式保存禁用状态——setup-wizard-window.ts(L99)在 URL 中不存在
aaEnabled参数时取false; - Safe Mode 无条件排除 AA,safe-mode.ts(L31-L35)中直接给出
aaEnabled: false; - 修改该选项时,Desktop 会先确认偏好已持久化,再调度一次应用重启(README 表述为 "Changing the option acknowledges persistence before scheduling a Desktop restart")。
在 main.ts(L1175)中,aaEnabled的读取与 Safe Mode 路径联动:
get aaEnabled() { return safeModePaths === undefined && profilePreferences?.aaEnabled === true }也就是说,Safe Mode 激活时该开关在逻辑层面恒为关闭,即使偏好文件里存着true。文案层面,desktop-settings-locales.ts(L15-L16)与 setup-wizard-copy.ts(L91-L92)负责中英文的呈现。启用之后,用户实际看到的就是 Agents Anywhere 在平板/手机端的会话界面:
启用之后:Profile 组装内部发生的三件事
开关只是入口,真正的复杂度在 Profile 组装阶段。以下流程集中在 profile.ts 的常量定义(L80-L81)与loadRecoveryFilteredProfile(L481-L570)中。
第一步,把 AA 塞进选中的 bundle 列表。逻辑只有一行:if (aaEnabled && !selectedBundles.includes(AA_PACKAGE_NAME)) selectedBundles.push(AA_PACKAGE_NAME)。这里AA_PACKAGE_NAME即@agents-anywhere/dsh-bridge-next。
第二步,通过 overlay 解析出包。Desktop 使用与 dshmarket 完全相同的 Desktop/Profile 包 overlay(resolveOverlayPackage,以INSTALL_ANCHOR和该 Profile 的package.json为基址)来定位包的实际安装位置——这一步保证 AA 包和其他市场插件走同一条解析通道,没有为它开任何特权路径。
第三步,读取并加载补丁声明。解析出的包内package.json必须声明dsh.bundle.patch字段;字段缺失或不是字符串,直接判定失败,随后加载对应补丁文件。
在prepareDesktopProfile(L949-L971)中,AA 层得到了特殊处理:从 AA bundle 的补丁中合成条目时,要求恰好存在一个未禁用的 canonical plugin entry——即row.id === 'agents-anywhere-bridge-next'且row.name === AA_PACKAGE_NAME,且匹配行数必须为 1,多一个少一个都不行。Desktop 随后保留 AA bundle 自己声明的补丁,只补充两样东西:真实的 DSH home(dshHome)与 Connector 的物理 payload 路径(connectorSourceDir)。Connector 目录会被重写为 ASAR unpacked 路径——lib/bundled-connector路径中的app.asar段替换为app.asar.unpacked(L962-L963),并校验pyproject.toml是否存在,以此确认 Python 源码确实随产物落地。
另一个关键设计是Desktop 不重写 AA 的stateRoot,也不为每个 Profile 发明独立的 DSH home。这意味着包本身继续持有登录、设备配对、账户存储以及它的原生运行时端点,AA 原生的账户/设备状态可以在多个 Profile 之间复用;而 Desktop 的启用/禁用偏好仍然按 Profile 隔离。两者解耦:壳管「要不要用」,包管「用的是哪个账户」。verify-profile-boot.mjs(L335-L340)里有对应的断言:启用 AA 后,它必须在自己的 DSH home 下发布agents-anywhere/bridge/endpoint.json;同时,一个全新 Profile 若继承了既有 AA 账户("A fresh Profile inherited an AA account"),验证直接判失败。
包的存放机制:vendor 内嵌 + 固定提交 + SHA-256 校验
@agents-anywhere/dsh-bridge-next不走 registry 的普通版本引用,而是以固定 tarball 收编在vendor/agents-anywhere/目录中:
vendor/agents-anywhere/ ├── README.md ├── agents-anywhere-dsh-bridge-next-0.1.0-dev.0.desktop.c00df092c98b2.rcda81994.tgz ├── agents-anywhere-dsh-bridge-next-0.1.0-dev.0.desktop.c63fc36855ba9.rcda81994.tgz ├── agents-anywhere-dsh-bridge-next-0.1.0-dev.0.desktop.ce53016f05be0.re9c8ad00.tgz └── provenance.json这种「vendor 内嵌」模式决定了几个运行时特性:桌面端消费的是打包好的 tarball,不需要邻近的 AA checkout;产物内已包含 Host 与浏览器(client)bundle、它们的 source map,以及 Python Connector 源码;AA 侧源码按原样进入产物,README 明确说明 "The source code is unchanged";产物 manifest 被重写为带 Desktop 标记的构建版本号,并为 Desktop 的两个运行时版本(0.1.5-rc.2与0.1.6-alpha.1)声明显式 peer 依赖,覆盖产物中实际出现的dsh-llm、dsh-session导入;每一个交付的 artifact 都由 SHA-256 校验和锁定,做到「source SHA + artifact checksum 精确定位到底发布了什么」。
dsh-plugin-desktop/package.json(L138 附近)中的依赖声明即本地文件引用:
"@agents-anywhere/dsh-bridge-next": "file:../vendor/agents-anywhere/agents-anywhere-dsh-bridge-next-0.1.0-dev.0.desktop.c00df092c98b2.rcda81994.tgz"provenance.json 字段速查
每次准备产物时都会生成或更新 vendor/agents-anywhere/provenance.json。以仓库当前记录为例(commite53016f05be0e000d5e6b9dfe7c319d1a2d02d50):
{ "repository": "https://github.com/anywhere-labs/Agents-Anywhere.git", "branch": "main", "commit": "e53016f05be0e000d5e6b9dfe7c319d1a2d02d50", "packageDirectory": "dsh-bridge-next", "sourceVersion": "0.1.0-dev.0", "desktopVersion": "0.1.0-dev.0.desktop.ce53016f05be0.re9c8ad00", "artifact": "agents-anywhere-dsh-bridge-next-0.1.0-dev.0.desktop.ce53016f05be0.re9c8ad00.tgz", "sha256": "4c6ba17bc3bb4c7cc61dbd81c268e846a6db4cbd48243035936737a064c52f40", "runtimePeers": { "@deepseek-ai/dsh-typert-protocol": "0.1.5-rc.2 || 0.1.6-alpha.1", "@deepseek-ai/dsh-llm": "0.1.5-rc.2 || 0.1.6-alpha.1", "@deepseek-ai/dsh-session": "0.1.5-rc.2 || 0.1.6-alpha.1" }, "manifestChanges": [], "sourceChanges": [] }| 字段 | 含义 |
|---|---|
repository/branch/commit | 产物源码来源:仓库地址、分支名、精确的 40 位提交 SHA |
packageDirectory | 被打包的上游子目录,固定为dsh-bridge-next |
sourceVersion | 上游原始版本,如0.1.0-dev.0 |
desktopVersion | 重写后的 Desktop 构建版本(命名规则见下) |
artifact | 生成的 tarball 文件名 |
sha256 | 产物 SHA-256 校验和,锁定实际交付物 |
runtimePeers | 为 Desktop 两个运行时版本生成的 peer 范围 |
manifestChanges | 对上游 manifest 的改动清单(版本号重写、移除 prepack/postpack 钩子、peer 声明) |
sourceChanges | 源码改动清单,当前始终为空数组(源码未改动) |
Desktop 版本号是怎么命名的
scripts/prepare-agents-anywhere-release.mjs 的versionForCommit(L43-L47)定义了命名算法:
<major>.<minor>.<patch>[-<prerelease>.]desktop.c<commit前12位>.r<peer范围JSON的SHA-256前8位>c段取自上游提交 SHA 的前 12 位(如c00df092c98b2、ce53016f05be0);r段来自对JSON.stringify(peerRanges)做 SHA-256 后取前 8 位,与两个 Desktop 变体当前声明的dsh-typert-protocol、dsh-llm、dsh-session依赖范围绑定。换句话说,产物版本同时键控于「源码提交」和「Desktop peer 范围」,任何一边变化都会产生新的版本号与新的 tarball。
这里要强调「旧产物保留」策略:新产物不会覆盖或删除旧产物(README 原文 "Old artifacts remain available"),这正是vendor/agents-anywhere/下并存多个*.tgz的原因。一个可以对照的现实:仓库当前provenance.json记录的最近一次准备提交为e53016f05be0e000d5e6b9dfe7c319d1a2d02d50(对应...ce53016f05be0.re9c8ad00.tgz),而 dsh-plugin-desktop/package.json 当时 pin 的是c00df092c98b2对应的产物——两份 tarball 同时躺在目录里,各自可追溯。
发布管线:aa:check 与 aa:prepare-release 如何分工
仓库根 package.json(L1168-L1188)里,dev、dev:beta、dist:*、package:dir*等命令统一先执行yarn aa:prepare-release,再进入各 workspace 的构建/打包步骤,例如:
"dev": "yarn aa:prepare-release && yarn workspace dsh-community-market build && yarn workspace dsh-plugin-desktop dev", "dist:mac:beta": "yarn aa:prepare-release && yarn workspace dsh-community-market build && yarn workspace dsh-plugin-desktop-beta dist:mac", "aa:check": "node scripts/prepare-agents-anywhere-release.mjs --check", "aa:prepare-release": "node scripts/prepare-agents-anywhere-release.mjs"aa:check是只读对比模式:脚本仅通过git ls-remote解析远程main头部提交(见 prepare 脚本 L94-L100),与provenance.json中已提交的提交比对,输出 "AA is up to date." 或提示存在可用更新,不做任何网络之外的写操作。aa:prepare-release则执行完整的prepare()(L113-L205),步骤如下:
- 解析源提交:若
DSH_AA_SOURCE_REF是 40 位完整 SHA 则直接使用;否则对该值(默认main)执行git ls-remote解析出单一提交; - 隔离 checkout:在临时目录
git init+ 添加 remote +git fetch --depth=1 --no-tags origin <commit>+ 分离检出(detached HEAD),并校验rev-parse HEAD与目标提交一致; - 复制源码子目录:将
dsh-bridge-next与connector复制到构建目录(copySourceTree会过滤.git、node_modules、.venv、__pycache__等); - 重写 manifest(
patchManifest):设置desktopVersion、删除 prepack/postpack 钩子、写入三个@deepseek-ai/*peer 范围; - 构建与打包:依次执行
yarn install --mode=skip-build、yarn build、yarn typecheck、yarn check:build,最后yarn pack --out产出唯一 tarball; - 落盘更新:生成/更新
provenance.json,将两个 Desktop 变体的package.json依赖指向新 tarball(file:../vendor/agents-anywhere/<artifact>),再在根目录执行一次yarn install --mode=skip-build刷新 lockfile。
环境变量与取值约束
| 变量 | 默认值 | 接受值 | 作用 |
|---|---|---|---|
DSH_AA_SOURCE_REF | main | 分支名 / 40 位完整 commit SHA /pinned | 指定 AA 源码来源引用;pinned表示直接使用已提交的 tarball |
DSH_AA_SOURCE_REPOSITORY | AA 公开 GitHub 仓库 | 任意 git 仓库 URL(例如带认证的 SSH 地址) | 更换 AA 源码仓库来源 |
DSH_VERIFY_AA | 未设置 | 1开启 | 配合verify:profile启用 AA 的无头冒烟验证 |
脚本在解析提交时会设置GIT_TERMINAL_PROMPT=0,避免 CI/无交互环境下因凭证提示挂起;单条命令超时上限为 600 秒。官方命令速查:
# 只读对比当前远程 main 头部 corepack yarn aa:check # 准备最新 AA 包(不打包 Electron) corepack yarn aa:prepare-release # 开发:先解析最新 AA,再启动 Desktop corepack yarn dev # 正常发布:先解析最新 AA,再打包 Desktop corepack yarn dist:mac:beta # 复现已提交的 AA 产物(不访问 GitHub) DSH_AA_SOURCE_REF=pinned corepack yarn dist:mac:beta # 指定精确的 40 位提交而不是移动分支 DSH_AA_SOURCE_REF=<commit> corepack yarn aa:prepare-releaseWindows PowerShell 下先执行$env:DSH_AA_SOURCE_REF = 'pinned'再运行 Yarn,切回最新构建前删除该变量。
失败回滚与 pinned 模式
管线对失败采取**硬失败(fail-closed)**策略:网络、源码构建或依赖安装任何一步失败都会中止打包,不会静默发布旧插件。失败时脚本会将四个文件做快照还原——dsh-plugin-desktop/package.json、dsh-plugin-desktop-beta/package.json、yarn.lock、vendor/agents-anywhere/provenance.json(见 prepare 脚本 L135-L136、L197-L201)——并删除未发布的临时 tarball。如果根目录安装已经开始,需要恢复后再重试:
corepack yarn install --immutableDSH_AA_SOURCE_REF=pinned走另一条路径:不做任何网络请求,直接校验已提交 tarball 的 SHA-256 与provenance.json记录是否一致(不匹配即抛错),并要求依赖已先被正常安装(因为跳过安装步骤)。这也是 CI 中复现已提交 pin 的标准方式——PR 的 CI 始终校验仓库里已提交的产物,而不是去查询 AA 的移动分支。
失效处理:预检、失败关闭与诊断边界
启用 AA 时,Desktop 会执行一层跟随市场加载边界的预检(preflight)。以下任一情况都会让该次 generation 的 AA 失效(disabled):
- bundle 缺失或格式错误;
- canonical entry 非法(非单一、非启用、ID/name 不匹配);
- Connector payload 缺失(找不到
pyproject.toml); - 存在与 AA 配置冲突的用户补丁("conflicting AA configuration was removed" 会触发失败)。
失败时 Desktop 会记录诊断信息,Settings 界面提供 retry(重试)动作。需要注意边界语义:预检只覆盖上述确定性问题,不会抑制插件在 Cordis 初始化阶段稍后抛出的任意错误("it does not suppress arbitrary errors thrown later by a plugin during Cordis initialization")。
源码侧对应aaFailure字段(profile.ts L465-L469):AA 层加载抛错时被捕获为aaFailure,而不阻断其余 bundle 的加载;host-bootstrap.ts 通过readAa()暴露{ requested, effective }对,让上层能感知「用户请求了但实际未生效」的状态。这个三元组语义很清晰:请求(requested)、生效(effective)、失败原因(aaFailure),三者共同构成排障时的完整证据链。
Connector 运行前提检查
AA 的 Python Connector 启动有三个硬性前提:uv必须位于PATH中,或通过环境变量UV_PATH显式指定;Python 3.12+;首次启动时可能下载 Python 依赖。
同时需要区分两个容易混淆的包:
@agents-anywhere/dsh-bridge-next:内置的bridge,即本文主题;@agents-anywhere/dsh-bridge(旧版):一个独立的用户插件,不在本选项的管辖范围内,它的配置不会被迁移或删除。
README 还强调:如果用户已单独安装过 Agents Anywhere 桌面应用,AA 包对其的原生处理仍然生效,不因 Desktop 集成而改变。
历史账户布局的兼容同样有明确承诺。更早的集成方式曾把 AA 账户写入每个 Profile 的agents-anywhere目录;这些文件被保留但不再自动选中——用户可能需要通过 AA 原生 state 目录登录一次。README 明确承诺:两个布局之间不会静默复制任何账户、凭据或设备绑定。
合入更新前的验证清单
无头冒烟:verify:aa 与 DSH_VERIFY_AA
Desktop 的check脚本链中包含verify:aa,其定义(dsh-plugin-desktop/package.json L134)为:
DSH_VERIFY_AA=1 node scripts/verify-profile-boot.mjsscripts/verify-profile-boot.mjs(L61-L73)是一个无头(headless)冒烟:它在临时 home 中调用真实的prepareDesktopProfile组装完整 DSH Web Profile,然后分档断言:
DSH_VERIFY_AA=1:以启用 AA 组装 Profile,断言 client 依赖图包含@agents-anywhere/dsh-bridge-next,且 Host 侧agentsAnywhereRuntime、agentsAnywhereOnboarding两个能力均已激活;DSH_VERIFY_AA_BROKEN=1:注入一个损坏的 AA 包(版本99.0.0、patch 指向不存在的missing.patch.yml),断言aaFailure存在且aaEnabled为 false——失败关闭被直接测试;- 其余断言覆盖 Profile 服务、agent presets、目录选择器、Web 认证 URL、renderer 清单等。
配套的自动化测试还有 host-process-integration.spec.ts(L15,分别以aaEnabled: false/true两种状态启动真实 Web Host)与 client-aa-settings.spec.ts(L70,校验设置界面文案)。
历史验证记录的适用边界
README 的 Validation history 章节记录了两轮更新,且每一轮结论只对各自命名的提交有效("The historical validation below applies only to its named commit"):
- 当前产物:由发布脚本从 AA v2 提交
c26402633cb840d376048b0bdb42c2db59e7cb33准备。build、typecheck、build-artifact 检查通过;两个 Desktop 变体均通过真实 AA Host/client Profile 加载;重复准备时复用了已验证产物。该轮未测试签名 Electron 包与交互式设备 onboarding。 - 上一轮手工准备:产物来自 AA v2 提交
ae47731c50f02033728faed1ba55f95c8008ec86,包含匹配的 Python Connector 源码。该更新修复了 fresh login 时的 deleted-device recovery、Windows discovery(避免os.kill(pid, 0))、Windows 安全的pwd导入;插件配置与 bundle 契约不变,dsh-session、dsh-llm、dsh-typert-protocol保持显式 Desktop 兼容 peer。在隔离源码导出中,TypeScript 检查、Host/client 构建、build artifact 与真实 Client factory DOM 检查全部通过;全部 111 个插件测试以--test-concurrency=1通过,35 个定向 Connector 测试通过(含 Windows 回归测试);其中包含受控的 Python/后端集成测试,但不包含交互式真实模型、手机或原生 Windows 验收测试。
采纳更新的四步操作清单
先验证再采纳:预检并不保证与未来所有 AA 变更兼容。合入前,两个 Desktop 变体都要跑真实验证:
DSH_VERIFY_AA=1 corepack yarn workspace <desktop-package> verify:profile其中
<desktop-package>为dsh-plugin-desktop或dsh-plugin-desktop-beta。验证 Connector 落盘位置:确认 Connector 源码被解包到
app.asar之外(即app.asar.unpacked),并针对匹配的 AA Server/Web 测试 onboarding;review 并提交四类变更:两个 Desktop 变体的依赖声明、
yarn.lock、provenance.json以及新 tarball 产物;认清边界:这些检查不构成对任意未来 AA 变更的兼容性保证,每轮验证结论只适用于该轮命名的提交。
小结
DeepSeek Harness Desktop 对 Agents Anywhere 桥接包的治理,本质上是一套「最小信任面」设计:vendor 内嵌保证产物可离线复现,固定提交加 SHA-256 保证可追溯,显式 peer 声明把运行时兼容写进 manifest,快照回滚加pinned模式保证管线可回滚;而在功能层面,Desktop 只注入dshHome与connectorSourceDir两个字段、不碰stateRoot,把登录、配对与账户存储的自主权完整留给 AA 自身。理解这套机制的价值在于:下一次 AA 上游有更新时,你知道哪些步骤必须跑、哪些字段必须 review、以及哪条验证结论对哪个提交才有效——这正是第三方依赖治理从「能用」走向「可控」的分界线。
【免费下载链接】deepseek-harness-desktop为 DeepSeek Harness (DSH) 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness-desktop
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考