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

推荐订阅源

S
SegmentFault 最新的问题
B
Blog
P
Proofpoint News Feed
美团技术团队
The GitHub Blog
The GitHub Blog
Y
Y Combinator Blog
A
About on SuperTechFans
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Vercel News
Vercel News
有赞技术团队
有赞技术团队
小众软件
小众软件
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
aimingoo的专栏
aimingoo的专栏
H
Help Net Security
罗磊的独立博客
L
LangChain Blog
GbyAI
GbyAI
腾讯CDC
T
The Blog of Author Tim Ferriss
Microsoft Security Blog
Microsoft Security Blog

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
test: tighten inline actions assertions · openclaw/opencl...
steipete · 2026-05-11 · via Recent Commits to openclaw:main

@@ -143,6 +143,33 @@ async function runInlineStatusAction(storePath?: string) {

143143

return { result, typing };

144144

}

145145146+

function requireRecord(value: unknown, label: string): Record<string, unknown> {

147+

expect(value).toBeTypeOf("object");

148+

expect(value).not.toBeNull();

149+

if (!value || typeof value !== "object" || Array.isArray(value)) {

150+

throw new Error(`expected ${label} to be an object`);

151+

}

152+

return value as Record<string, unknown>;

153+

}

154+155+

function mockObjectArg(mock: ReturnType<typeof vi.fn>, label: string, callIndex = 0, argIndex = 0) {

156+

const call = mock.mock.calls[callIndex];

157+

expect(call).toBeDefined();

158+

if (!call) {

159+

throw new Error(`expected ${label} mock call ${callIndex}`);

160+

}

161+

return requireRecord(call[argIndex], `${label} argument ${argIndex}`);

162+

}

163+164+

function mockCallArgs(mock: ReturnType<typeof vi.fn>, label: string, callIndex = 0): unknown[] {

165+

const call = mock.mock.calls[callIndex] as unknown[] | undefined;

166+

expect(call).toBeDefined();

167+

if (!call) {

168+

throw new Error(`expected ${label} mock call ${callIndex}`);

169+

}

170+

return call;

171+

}

172+146173

describe("handleInlineActions", () => {

147174

beforeEach(() => {

148175

handleCommandsMock.mockReset();

@@ -207,11 +234,7 @@ describe("handleInlineActions", () => {

207234208235

expect(result).toEqual({ kind: "reply", reply: { text: "done" } });

209236

expect(handleCommandsMock).toHaveBeenCalledTimes(1);

210-

expect(handleCommandsMock).toHaveBeenCalledWith(

211-

expect.objectContaining({

212-

agentDir,

213-

}),

214-

);

237+

expect(mockObjectArg(handleCommandsMock, "handleCommands").agentDir).toBe(agentDir);

215238

});

216239217240

it("prefers the target session entry when routing inline commands into handleCommands", async () => {

@@ -252,12 +275,9 @@ describe("handleInlineActions", () => {

252275

);

253276254277

expect(result).toEqual({ kind: "reply", reply: { text: "done" } });

255-

expect(handleCommandsMock).toHaveBeenCalledWith(

256-

expect.objectContaining({

257-

sessionEntry: expect.objectContaining({

258-

sessionId: "target-session",

259-

}),

260-

}),

278+

const commandArgs = mockObjectArg(handleCommandsMock, "handleCommands");

279+

expect(requireRecord(commandArgs.sessionEntry, "sessionEntry").sessionId).toBe(

280+

"target-session",

261281

);

262282

});

263283

@@ -266,11 +286,7 @@ describe("handleInlineActions", () => {

266286267287

expect(result).toEqual({ kind: "reply", reply: undefined });

268288

expect(buildStatusReplyMock).toHaveBeenCalledTimes(1);

269-

expect(buildStatusReplyMock).toHaveBeenCalledWith(

270-

expect.objectContaining({

271-

storePath: undefined,

272-

}),

273-

);

289+

expect(mockObjectArg(buildStatusReplyMock, "buildStatusReply").storePath).toBeUndefined();

274290

expect(handleCommandsMock).not.toHaveBeenCalled();

275291

expect(typing.cleanup).toHaveBeenCalled();

276292

});

@@ -279,10 +295,8 @@ describe("handleInlineActions", () => {

279295

const { result } = await runInlineStatusAction("/tmp/inline-status-store.json");

280296281297

expect(result).toEqual({ kind: "reply", reply: undefined });

282-

expect(buildStatusReplyMock).toHaveBeenCalledWith(

283-

expect.objectContaining({

284-

storePath: "/tmp/inline-status-store.json",

285-

}),

298+

expect(mockObjectArg(buildStatusReplyMock, "buildStatusReply").storePath).toBe(

299+

"/tmp/inline-status-store.json",

286300

);

287301

expect(handleCommandsMock).not.toHaveBeenCalled();

288302

});

@@ -325,15 +339,11 @@ describe("handleInlineActions", () => {

325339

);

326340327341

expect(result).toEqual({ kind: "reply", reply: undefined });

328-

expect(buildStatusReplyMock).toHaveBeenCalledWith(

329-

expect.objectContaining({

330-

sessionEntry: expect.objectContaining({

331-

sessionId: "target-session",

332-

parentSessionKey: "target-parent",

333-

}),

334-

parentSessionKey: "target-parent",

335-

}),

336-

);

342+

const statusArgs = mockObjectArg(buildStatusReplyMock, "buildStatusReply");

343+

const statusSessionEntry = requireRecord(statusArgs.sessionEntry, "status sessionEntry");

344+

expect(statusSessionEntry.sessionId).toBe("target-session");

345+

expect(statusSessionEntry.parentSessionKey).toBe("target-parent");

346+

expect(statusArgs.parentSessionKey).toBe("target-parent");

337347

expect(handleCommandsMock).not.toHaveBeenCalled();

338348

});

339349

@@ -564,12 +574,9 @@ describe("handleInlineActions", () => {

564574

expect(ctx.Body).toBe(

565575

"Act as an engineering advisor.\n\nFocus on:\nbuild me a deployment plan",

566576

);

567-

expect(handleCommandsMock).toHaveBeenCalledWith(

568-

expect.objectContaining({

569-

ctx: expect.objectContaining({

570-

Body: "Act as an engineering advisor.\n\nFocus on:\nbuild me a deployment plan",

571-

}),

572-

}),

577+

const commandArgs = mockObjectArg(handleCommandsMock, "handleCommands");

578+

expect(requireRecord(commandArgs.ctx, "handleCommands ctx").Body).toBe(

579+

"Act as an engineering advisor.\n\nFocus on:\nbuild me a deployment plan",

573580

);

574581

});

575582

@@ -624,11 +631,9 @@ describe("handleInlineActions", () => {

624631

);

625632626633

expect(result).toEqual({ kind: "reply", reply: { text: "✅ Done." } });

627-

expect(createOpenClawToolsMock).toHaveBeenCalledWith(

628-

expect.objectContaining({

629-

requesterAgentIdOverride: "named-worker",

630-

}),

631-

);

634+

expect(

635+

mockObjectArg(createOpenClawToolsMock, "createOpenClawTools").requesterAgentIdOverride,

636+

).toBe("named-worker");

632637

expect(toolExecute).toHaveBeenCalled();

633638

});

634639

@@ -682,20 +687,15 @@ describe("handleInlineActions", () => {

682687

);

683688684689

expect(result).toEqual({ kind: "reply", reply: { text: "✅ Done." } });

685-

expect(createOpenClawToolsMock).toHaveBeenCalledWith(

686-

expect.objectContaining({

687-

senderIsOwner: true,

688-

}),

689-

);

690-

expect(toolExecute).toHaveBeenCalledWith(

691-

expect.stringMatching(/^cmd_/),

692-

{

693-

command: "display name",

694-

commandName: "set_profile",

695-

skillName: "matrix-profile",

696-

},

697-

undefined,

698-

);

690+

expect(mockObjectArg(createOpenClawToolsMock, "createOpenClawTools").senderIsOwner).toBe(true);

691+

const toolCall = mockCallArgs(toolExecute, "toolExecute");

692+

expect(toolCall?.[0]).toMatch(/^cmd_/);

693+

expect(toolCall?.[1]).toEqual({

694+

command: "display name",

695+

commandName: "set_profile",

696+

skillName: "matrix-profile",

697+

});

698+

expect(toolCall?.[2]).toBeUndefined();

699699

});

700700701701

it("honors construction-time before-tool-call blocks for inline tool dispatch", async () => {

@@ -778,21 +778,17 @@ describe("handleInlineActions", () => {

778778

kind: "reply",

779779

reply: { text: "❌ Tool call blocked: denied by policy" },

780780

});

781-

expect(createOpenClawToolsMock).toHaveBeenCalledWith(

782-

expect.objectContaining({

783-

sessionId: "target-session",

784-

currentChannelId: "whatsapp",

785-

}),

786-

);

787-

expect(toolExecute).toHaveBeenCalledWith(

788-

expect.stringMatching(/^cmd_/),

789-

{

790-

command: "display name",

791-

commandName: "set_profile",

792-

skillName: "matrix-profile",

793-

},

794-

abortController.signal,

795-

);

781+

const toolsArgs = mockObjectArg(createOpenClawToolsMock, "createOpenClawTools");

782+

expect(toolsArgs.sessionId).toBe("target-session");

783+

expect(toolsArgs.currentChannelId).toBe("whatsapp");

784+

const blockedToolCall = mockCallArgs(toolExecute, "toolExecute");

785+

expect(blockedToolCall?.[0]).toMatch(/^cmd_/);

786+

expect(blockedToolCall?.[1]).toEqual({

787+

command: "display name",

788+

commandName: "set_profile",

789+

skillName: "matrix-profile",

790+

});

791+

expect(blockedToolCall?.[2]).toBe(abortController.signal);

796792

expect(typing.cleanup).toHaveBeenCalled();

797793

});

798794

});