fix: allow remote Execute without bubblewrap

Remote Hosts without the Ask-only bubblewrap tool could report matching Agent and Runtime versions but fail project creation because the Agent hid the Runtime ACP capability entirely. The Agent now advertises a verified Runtime independently of bubblewrap, so Execute can start directly while Ask keeps its existing read-only bubblewrap boundary.

Release note: 修复远程 Host 缺少 bubblewrap 时 Execute 项目无法创建的问题;更新到 Agent 0.11.16 后,Execute 不再受 Ask 专用系统工具影响。
This commit is contained in:
mesalogo
2026-09-03 15:59:05 +08:00
parent 74c3ec19b4
commit 987a08ad78
4 changed files with 13 additions and 25 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"formatVersion": 1,
"agentVersion": "0.11.15",
"agentVersion": "0.11.16",
"protocol": {
"major": 2,
"minor": 0
@@ -12,7 +12,7 @@ Linux x64/arm64、取消和离线 GoodBuddy 传输的真实 Host 验收。
Windows 到 Linux x64 的安装、Agent-owned Prompt、Agent 本地模型 gateway、断线恢复、
同一 OpenCode Session 续接、取消和终态清理已经使用真实模型与工具验证。Agent
`0.11.14` 已通过独立 workflow 发布 Linux x64/arm64 复合包和签名累计目录;当前未发布
Agent 源码 lock 为 `0.11.15`,Desktop 恢复候选为 `0.12.2`,等待各自独立发布审批。
Agent 源码 lock 为 `0.11.16`,Desktop 恢复候选为 `0.12.2`,等待各自独立发布审批。
现有源码显示本地与远端 OpenCode 原生 Task,并取消 GoodBuddy 对生产 Prompt 的
固定墙钟总时限。失败的 `agent-v0.11.3` 保持不可变且未发布。
@@ -192,7 +192,8 @@ Ask 使用系统 `bwrap`:
search、edit、execute、未知工具以及只提供持久授权的请求全部拒绝。
`allow_once` 只解决 OpenCode 发起原生读取前的 ACP 协商,真正的文件系统边界仍是只读
`bwrap` bind。Host 缺少 `bwrap` 时 Ask 不可用。
`bwrap` bind。Host 缺少 `bwrap` 时 Ask 启动失败,但不影响 Runtime 能力声明或 Execute
直接启动。
### Execute
@@ -349,7 +350,7 @@ model bridge,以及生命周期和恢复逻辑。单元测试、mock、fixture
- 2026-08 的本地 fixture 完整验证 Linux x64 Agent `0.11.2-e2e.12`、Node `24.19.0`
和 Agent protocol `2.0`;当时没有 arm64 fixture,因此该记录不能作为当前独立发布
的双架构验收。Agent `0.11.10` 后续已由原生 workflow 发布并公开验证双架构工件;
当前源码 lock 固定为 `0.11.15`;正式发布状态以独立 Agent Release 与签名 catalog 为准。
当前源码 lock 固定为 `0.11.16`;正式发布状态以独立 Agent Release 与签名 catalog 为准。
- 2026-08-30 在共享 Linux x64 Host 的隔离测试 HOME 中验证当前 `0.11.13` 源码候选:
签名 Runtime 清单的测试墙钟上限为 1 秒,模型桥首轮故意延迟 2.515 秒后 Prompt 仍在
5.770 秒正常完成;随后 OpenCode 原生 Task 依次产生 `running`、`completed` 子 Agent
@@ -397,6 +398,11 @@ model bridge,以及生命周期和恢复逻辑。单元测试、mock、fixture
workflow 与 Release Notes 聚焦测试 `106/106` 通过、1 项平台用例跳过;全量
`npm test` 为 `3478` 通过、`51` 跳过,typecheck 与 lint 通过。本轮没有新增模型调用,
也未在本地运行 production build、package 或安装探针。
- 2026-09-03 使用包含当前 Runtime capability 修复的源码 harness,在共享 Linux x64 Host
的唯一 `/tmp/goodbuddy-e2e-runtime-capability-*` 隔离 HOME 中读取签名 Runtime 副本。
Agent 成功报告已登记 OpenCode Runtime,Execute 随后直接启动 OpenCode 而未经过
`bwrap`;Runtime owner 和隔离目录均已清理,未修改 Host current Agent/Runtime。
本次只验证能力声明和真实进程启动,没有发送 Prompt,真实文本模型调用 0 次。
- 正常 Host 更新路径把 Linux x64 Host 的 Agent 更新为 `0.11.2-e2e.12`,并确认
OpenCode Runtime 已安装版本与所需版本均为 `1.18.9`。
- 一条新的 Ask 用户操作只提交一次。OpenCode 先在 build 模型轮次请求一个原生
+2 -4
View File
@@ -37,7 +37,7 @@ afterEach(() => {
})
describe('production Runtime composition', () => {
it('loads metadata installed after startup and caches the registered Runtime identity', async () => {
it('loads Runtime metadata independently of Ask-only Host prerequisites', async () => {
const fixture = await createRuntimeBundleTestFixture()
const root = fixture.root
temporaryPaths.push(root)
@@ -62,7 +62,6 @@ describe('production Runtime composition', () => {
blobSink: async () => {},
agentExecutablePath,
reportError,
prerequisitesAvailable: async () => true,
verificationEnvironment: 'test',
filesystemPlatform: 'win32'
})
@@ -128,7 +127,7 @@ describe('production Runtime composition', () => {
events.close()
})
it('composes all autonomous ACP methods but advertises no Runtime when prerequisites fail', async () => {
it('composes all autonomous ACP methods when no Runtime is installed', async () => {
const root = temporaryDirectory()
const runtimeRoot = resolve(root, 'runtimes')
const stateDirectory = resolve(root, 'state')
@@ -155,7 +154,6 @@ describe('production Runtime composition', () => {
releaseKeyRegistry,
runtimeLock: {} as RemoteRuntimeLock,
registry,
prerequisitesAvailable: async () => false,
verificationEnvironment: 'test',
filesystemPlatform: 'win32'
})
+1 -17
View File
@@ -46,8 +46,6 @@ import {
} from './agent-model-gateway'
import type { AgentDiagnosticLog } from './diagnostic-log'
const BWRAP_EXECUTABLE = '/usr/bin/bwrap'
export type ProductionRuntimeProtocol = {
runtimes: ReturnType<typeof createVerifiedRuntimeCapabilitySource>
methods: RuntimeAcpBackend['methods']
@@ -85,7 +83,6 @@ export type ProductionRuntimeCompositionOptions = {
releaseKeyRegistry?: AgentReleaseKeyRegistry
runtimeLock?: RemoteRuntimeLock
registry?: RuntimeBundleRegistry
prerequisitesAvailable?: () => boolean | Promise<boolean>
launchProcess?: typeof launchDirectLinuxStdioProcessOwner
reconcileOrphanedProcesses?: (
installationId: string
@@ -222,9 +219,6 @@ export async function createProductionRuntimeProtocol(
})
return await source()
}
const prerequisites =
options.prerequisitesAvailable ??
productionRuntimePrerequisitesAvailable
const launchProcess =
options.launchProcess ?? launchDirectLinuxStdioProcessOwner
let backend: RuntimeAcpBackend
@@ -328,8 +322,7 @@ export async function createProductionRuntimeProtocol(
options.agentExecutablePath === undefined ||
!(await executableAvailable(
resolve(options.agentExecutablePath)
)) ||
!(await prerequisites())
))
) {
return []
}
@@ -540,12 +533,3 @@ function bindingDirectoryDigest(
]))
.digest('hex')
}
async function productionRuntimePrerequisitesAvailable(): Promise<boolean> {
try {
await access(BWRAP_EXECUTABLE, constants.X_OK)
return true
} catch {
return false
}
}