惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
L
LangChain Blog
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
宝玉的分享
宝玉的分享
B
Blog RSS Feed
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
D
Docker
B
Blog
Engineering at Meta
Engineering at Meta
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
I
InfoQ
G
Google Developers Blog
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The GitHub Blog
The GitHub Blog
T
The Blog of Author Tim Ferriss
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
U
Unit 42

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix: harden acpx openclaw bridge routing · openclaw/openc...
steipete · 2026-04-23 · via Recent Commits to openclaw:main

@@ -7,6 +7,9 @@ type TestSessionStore = {

77

save(record: Record<string, unknown>): Promise<void>;

88

};

9910+

const DOCUMENTED_OPENCLAW_BRIDGE_COMMAND =

11+

"env OPENCLAW_HIDE_BANNER=1 OPENCLAW_SUPPRESS_NOTES=1 openclaw acp --url ws://127.0.0.1:18789 --token-file ~/.openclaw/gateway.token --session agent:main:main";

12+1013

function makeRuntime(

1114

baseStore: TestSessionStore,

1215

options: Partial<ConstructorParameters<typeof AcpxRuntime>[0]> = {},

@@ -17,11 +20,15 @@ function makeRuntime(

1720

close: AcpRuntime["close"];

1821

ensureSession: AcpRuntime["ensureSession"];

1922

getStatus: NonNullable<AcpRuntime["getStatus"]>;

23+

isHealthy(): boolean;

24+

probeAvailability(): Promise<void>;

2025

};

2126

bridgeSafeDelegate: {

2227

close: AcpRuntime["close"];

2328

ensureSession: AcpRuntime["ensureSession"];

2429

getStatus: NonNullable<AcpRuntime["getStatus"]>;

30+

isHealthy(): boolean;

31+

probeAvailability(): Promise<void>;

2532

};

2633

} {

2734

const runtime = new AcpxRuntime({

@@ -48,6 +55,8 @@ function makeRuntime(

4855

close: AcpRuntime["close"];

4956

ensureSession: AcpRuntime["ensureSession"];

5057

getStatus: NonNullable<AcpRuntime["getStatus"]>;

58+

isHealthy(): boolean;

59+

probeAvailability(): Promise<void>;

5160

};

5261

}

5362

).delegate,

@@ -57,6 +66,8 @@ function makeRuntime(

5766

close: AcpRuntime["close"];

5867

ensureSession: AcpRuntime["ensureSession"];

5968

getStatus: NonNullable<AcpRuntime["getStatus"]>;

69+

isHealthy(): boolean;

70+

probeAvailability(): Promise<void>;

6071

};

6172

}

6273

).bridgeSafeDelegate,

@@ -130,7 +141,7 @@ describe("AcpxRuntime fresh reset wrapper", () => {

130141

discardPersistentState: true,

131142

});

132143

expect(await wrappedStore.load("agent:codex:acp:binding:test")).toBeUndefined();

133-

expect(baseStore.load).not.toHaveBeenCalled();

144+

expect(baseStore.load).toHaveBeenCalledOnce();

134145

});

135146136147

it("routes openclaw ensureSession through the bridge-safe delegate when MCP servers are configured", async () => {

@@ -292,4 +303,141 @@ describe("AcpxRuntime fresh reset wrapper", () => {

292303

expect(bridgeEnsure).toHaveBeenCalledOnce();

293304

expect(defaultEnsure).not.toHaveBeenCalled();

294305

});

306+307+

it("uses the bridge-safe delegate for documented env-wrapped openclaw bridge commands", async () => {

308+

const baseStore: TestSessionStore = {

309+

load: vi.fn(async () => undefined),

310+

save: vi.fn(async () => {}),

311+

};

312+313+

const { runtime, delegate, bridgeSafeDelegate } = makeRuntime(baseStore, {

314+

mcpServers: [{ name: "tools", command: "mcp-tools" }] as never,

315+

agentRegistry: {

316+

resolve: (agentName: string) =>

317+

agentName === "openclaw" ? DOCUMENTED_OPENCLAW_BRIDGE_COMMAND : agentName,

318+

list: () => ["codex", "openclaw"],

319+

},

320+

});

321+

const defaultEnsure = vi.spyOn(delegate, "ensureSession").mockResolvedValue({

322+

sessionKey: "agent:openclaw:acp:test",

323+

backend: "acpx",

324+

runtimeSessionName: "default",

325+

});

326+

const bridgeEnsure = vi.spyOn(bridgeSafeDelegate, "ensureSession").mockResolvedValue({

327+

sessionKey: "agent:openclaw:acp:test",

328+

backend: "acpx",

329+

runtimeSessionName: "bridge",

330+

});

331+332+

const result = await runtime.ensureSession({

333+

sessionKey: "agent:openclaw:acp:test",

334+

agent: "openclaw",

335+

mode: "persistent",

336+

});

337+338+

expect(result.runtimeSessionName).toBe("bridge");

339+

expect(bridgeEnsure).toHaveBeenCalledOnce();

340+

expect(defaultEnsure).not.toHaveBeenCalled();

341+

});

342+343+

it("uses the bridge-safe delegate for local node openclaw entrypoints", async () => {

344+

const baseStore: TestSessionStore = {

345+

load: vi.fn(async () => undefined),

346+

save: vi.fn(async () => {}),

347+

};

348+349+

const { runtime, delegate, bridgeSafeDelegate } = makeRuntime(baseStore, {

350+

mcpServers: [{ name: "tools", command: "mcp-tools" }] as never,

351+

agentRegistry: {

352+

resolve: (agentName: string) =>

353+

agentName === "openclaw" ? "env OPENCLAW_HIDE_BANNER=1 node openclaw.mjs acp" : agentName,

354+

list: () => ["codex", "openclaw"],

355+

},

356+

});

357+

const defaultEnsure = vi.spyOn(delegate, "ensureSession").mockResolvedValue({

358+

sessionKey: "agent:openclaw:acp:test",

359+

backend: "acpx",

360+

runtimeSessionName: "default",

361+

});

362+

const bridgeEnsure = vi.spyOn(bridgeSafeDelegate, "ensureSession").mockResolvedValue({

363+

sessionKey: "agent:openclaw:acp:test",

364+

backend: "acpx",

365+

runtimeSessionName: "bridge",

366+

});

367+368+

const result = await runtime.ensureSession({

369+

sessionKey: "agent:openclaw:acp:test",

370+

agent: "openclaw",

371+

mode: "persistent",

372+

});

373+374+

expect(result.runtimeSessionName).toBe("bridge");

375+

expect(bridgeEnsure).toHaveBeenCalledOnce();

376+

expect(defaultEnsure).not.toHaveBeenCalled();

377+

});

378+379+

it("routes follow-up calls by persisted agent command before current config", async () => {

380+

const baseStore: TestSessionStore = {

381+

load: vi.fn(async () => ({

382+

acpxRecordId: "agent:openclaw:acp:test",

383+

agentCommand: DOCUMENTED_OPENCLAW_BRIDGE_COMMAND,

384+

})),

385+

save: vi.fn(async () => {}),

386+

};

387+388+

const { runtime, delegate, bridgeSafeDelegate } = makeRuntime(baseStore, {

389+

mcpServers: [{ name: "tools", command: "mcp-tools" }] as never,

390+

agentRegistry: {

391+

resolve: (agentName: string) => (agentName === "openclaw" ? "codex" : agentName),

392+

list: () => ["codex", "openclaw"],

393+

},

394+

});

395+

const defaultStatus = vi.spyOn(delegate, "getStatus").mockResolvedValue({

396+

summary: "default",

397+

});

398+

const bridgeStatus = vi.spyOn(bridgeSafeDelegate, "getStatus").mockResolvedValue({

399+

summary: "bridge",

400+

});

401+402+

const status = await runtime.getStatus({

403+

handle: {

404+

sessionKey: "agent:openclaw:acp:test",

405+

backend: "acpx",

406+

runtimeSessionName: "agent:openclaw:acp:test",

407+

},

408+

});

409+410+

expect(status.summary).toBe("bridge");

411+

expect(bridgeStatus).toHaveBeenCalledOnce();

412+

expect(defaultStatus).not.toHaveBeenCalled();

413+

});

414+415+

it("probes through the bridge-safe delegate when probeAgent resolves to openclaw bridge", async () => {

416+

const baseStore: TestSessionStore = {

417+

load: vi.fn(async () => undefined),

418+

save: vi.fn(async () => {}),

419+

};

420+421+

const { runtime, delegate, bridgeSafeDelegate } = makeRuntime(baseStore, {

422+

mcpServers: [{ name: "tools", command: "mcp-tools" }] as never,

423+

probeAgent: "openclaw",

424+

agentRegistry: {

425+

resolve: (agentName: string) =>

426+

agentName === "openclaw" ? DOCUMENTED_OPENCLAW_BRIDGE_COMMAND : agentName,

427+

list: () => ["codex", "openclaw"],

428+

},

429+

});

430+

const defaultProbe = vi.spyOn(delegate, "probeAvailability").mockResolvedValue(undefined);

431+

const bridgeProbe = vi

432+

.spyOn(bridgeSafeDelegate, "probeAvailability")

433+

.mockResolvedValue(undefined);

434+

vi.spyOn(delegate, "isHealthy").mockReturnValue(false);

435+

vi.spyOn(bridgeSafeDelegate, "isHealthy").mockReturnValue(true);

436+437+

await runtime.probeAvailability();

438+439+

expect(runtime.isHealthy()).toBe(true);

440+

expect(bridgeProbe).toHaveBeenCalledOnce();

441+

expect(defaultProbe).not.toHaveBeenCalled();

442+

});

295443

});