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

推荐订阅源

A
About on SuperTechFans
G
Google Developers Blog
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
云风的 BLOG
云风的 BLOG
小众软件
小众软件
月光博客
月光博客
Recent Announcements
Recent Announcements
人人都是产品经理
人人都是产品经理
P
Proofpoint News Feed
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
The Cloudflare Blog
博客园_首页
美团技术团队
大猫的无限游戏
大猫的无限游戏
B
Blog
IT之家
IT之家
Jina AI
Jina AI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
Check Point 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
fix: prompt Codex to send visible channel replies (#84397...
joshavant · 2026-05-20 · via Recent Commits to openclaw:main

File tree

  • extensions/codex/src/app-server

  • src

    • agents/tools

    • auto-reply/reply

    • gateway

  • test

    • fixtures/agents/prompt-snapshots/codex-runtime-happy-path

    • helpers/agents

Original file line numberDiff line numberDiff line change

@@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai

2929

- Docker: keep the bundled Codex plugin in official release image keep lists so the default OpenAI agent harness remains available after Docker pruning. Fixes #83613. (#83626) Thanks @YuanHanzhong.

3030

- CLI/channels: preserve the first line of `openclaw channels logs` output when the rolling tail window starts exactly on a line boundary, mirroring the already-fixed `readLogSlice` behavior in `src/logging/log-tail.ts`.

3131

- Control UI: treat terminal session status as authoritative over stale active-run flags so completed terminal runs stop showing abort/live UI. (#84057)

32+

- Codex/message: tell message-tool-only Codex turns to send visible channel output with `message(action="send")` before ending, so direct replies do not stay private. Fixes #84129. (#84397) Thanks @joshavant.

3233

- CLI: preserve embedded equals signs in inline root option values instead of truncating after the second separator. (#83995) Thanks @ThiagoCAltoe.

3334

- Matrix/config: accept `messages.queue.byChannel.matrix` queue overrides and keep queue provider schema/type keys aligned for Matrix, Google Chat, and Mattermost. Thanks @bdjben.

3435

- CLI: format `openclaw acp client` failures through the shared error formatter so object-shaped errors stay readable instead of printing `[object Object]`. Fixes #83904. (#84080)

Original file line numberDiff line numberDiff line change

@@ -1402,7 +1402,12 @@ describe("runCodexAppServerAttempt", () => {

14021402

testing.buildDeveloperInstructions(params, {

14031403

dynamicTools: [createMessageDynamicTool("Message test tool")],

14041404

}),

1405-

).toContain("To send a visible message, use the `message` tool.");

1405+

).toContain('call `message` with `action="send"` before ending the turn');

1406+

expect(

1407+

testing.buildDeveloperInstructions(params, {

1408+

dynamicTools: [createMessageDynamicTool("Message test tool")],

1409+

}),

1410+

).toContain("Do not rely on normal final assistant text for visible delivery");

14061411
14071412

const withoutMessageToolInstructions = testing.buildDeveloperInstructions(params, {

14081413

dynamicTools: [],

@@ -1413,7 +1418,7 @@ describe("runCodexAppServerAttempt", () => {

14131418

params.sourceReplyDeliveryMode = "automatic";

14141419

const automaticInstructions = testing.buildDeveloperInstructions(params);

14151420

expect(automaticInstructions).toContain("active Codex delivery path");

1416-

expect(automaticInstructions).not.toContain("use the `message` tool");

1421+

expect(automaticInstructions).not.toContain('call `message` with `action="send"`');

14171422

});

14181423
14191424

it("includes Codex app-server scoped plugin command guidance in developer instructions", () => {

Original file line numberDiff line numberDiff line change

@@ -884,7 +884,12 @@ function buildVisibleReplyInstruction(

884884

? dynamicTools.some((tool) => tool.name.trim() === "message")

885885

: params.disableMessageTool !== true;

886886

if (params.sourceReplyDeliveryMode === "message_tool_only" && messageToolAvailable) {

887-

return "To send a visible message, use the `message` tool.";

887+

return [

888+

"Preserve channel/session context.",

889+

'If this turn needs visible output in the current channel, call `message` with `action="send"` before ending the turn.',

890+

"Do not rely on normal final assistant text for visible delivery; final text is private to OpenClaw/Codex in this mode.",

891+

'If no visible channel response is needed, do not call `message(action="send")`.',

892+

].join(" ");

888893

}

889894

return "To send a visible reply, use the active Codex delivery path.";

890895

}

Original file line numberDiff line numberDiff line change

@@ -385,16 +385,18 @@ describe("message tool secret scoping", () => {

385385

const defaultTool = createMessageTool();

386386
387387

expect(scopedTool.description).toContain(

388-

'use action="send" with message for visible replies to the current source conversation',

388+

'if visible output is needed in the current source conversation, call action="send" with message before ending',

389389

);

390390

expect(scopedTool.description).toContain("target defaults to the current source conversation");

391-

expect(scopedTool.description).toContain("Normal final answers stay private");

391+

expect(scopedTool.description).toContain(

392+

"Normal final answers stay private and are not visible in this mode",

393+

);

392394

expect(explicitTargetTool.description).toContain("Include target when sending");

393395

expect(explicitTargetTool.description).not.toContain(

394396

"target defaults to the current source conversation",

395397

);

396398

expect(defaultTool.description).not.toContain(

397-

"visible replies to the current source conversation",

399+

"if visible output is needed in the current source conversation",

398400

);

399401

});

400402

@@ -405,7 +407,7 @@ describe("message tool secret scoping", () => {

405407

}).find((candidate) => candidate.name === "message");

406408
407409

expect(tool?.description).toContain(

408-

'use action="send" with message for visible replies to the current source conversation',

410+

'if visible output is needed in the current source conversation, call action="send" with message before ending',

409411

);

410412

});

411413
Original file line numberDiff line numberDiff line change

@@ -859,7 +859,7 @@ function appendMessageToolVisibleReplyHint(

859859

const targetGuidance = requireExplicitTarget

860860

? "Include target when sending."

861861

: "target defaults to the current source conversation; omit unless sending elsewhere.";

862-

return `${description} This turn: use action="send" with message for visible replies to the current source conversation. ${targetGuidance} Normal final answers stay private.`;

862+

return `${description} This turn: if visible output is needed in the current source conversation, call action="send" with message before ending. ${targetGuidance} Normal final answers stay private and are not visible in this mode.`;

863863

}

864864
865865

function appendMessageToolReadHint(

Original file line numberDiff line numberDiff line change

@@ -513,7 +513,7 @@ describe("tryDispatchAcpReply", () => {

513513

expect(managerMocks.runTurn).toHaveBeenCalledTimes(1);

514514

const text = runTurnCall().text;

515515

expect(text).toContain("Source channel delivery is private by default");

516-

expect(text).toContain("message(action=send)");

516+

expect(text).toContain('call `message` with `action="send"` before ending');

517517

expect(text).toContain("The target defaults to the current source channel");

518518

expect(text).toContain("reply privately unless you send explicitly");

519519

});

Original file line numberDiff line numberDiff line change

@@ -127,7 +127,7 @@ function resolveAcpTurnText(params: {

127127

[

128128

"Source channel delivery is private by default for this turn.",

129129

"Normal ACP final output will not be automatically posted to the source channel.",

130-

"To send visible output, use message(action=send). The target defaults to the current source channel.",

130+

'If visible output is needed in the current source channel, call `message` with `action="send"` before ending. The target defaults to the current source channel.',

131131

].join(" "),

132132

);

133133

return params.promptText ? `${guidance}\n\n${params.promptText}` : guidance;

Original file line numberDiff line numberDiff line change

@@ -45,11 +45,11 @@ describe("group runtime loading", () => {

4545

silentToken: "NO_REPLY",

4646

});

4747

expect(toolOnlyContext).toContain("Normal final replies are private");

48-

expect(toolOnlyContext).toContain("message tool with action=send");

48+

expect(toolOnlyContext).toContain('message tool with action="send" before ending');

4949

expect(toolOnlyContext).toContain("Be a good group participant");

5050

expect(toolOnlyContext).toContain("wrap bare URLs");

5151

expect(toolOnlyContext).toContain("<https://example.com>");

52-

expect(toolOnlyContext).toContain("do not call message(action=send)");

52+

expect(toolOnlyContext).toContain('do not call message(action="send")');

5353

expect(toolOnlyContext).not.toContain('reply with exactly "NO_REPLY"');

5454

expect(

5555

isolatedGroups.buildGroupIntro({

@@ -82,8 +82,8 @@ describe("group runtime loading", () => {

8282

sourceReplyDeliveryMode: "message_tool_only",

8383

});

8484

expect(toolOnlyContext).toContain("Normal final replies are private");

85-

expect(toolOnlyContext).toContain("message tool with action=send");

86-

expect(toolOnlyContext).toContain("do not call message(action=send)");

85+

expect(toolOnlyContext).toContain('message tool with action="send" before ending');

86+

expect(toolOnlyContext).toContain('do not call message(action="send")');

8787

expect(toolOnlyContext).not.toContain("NO_REPLY");

8888

expect(toolOnlyContext).not.toContain("Your replies are automatically sent");

8989

});

Original file line numberDiff line numberDiff line change

@@ -231,7 +231,7 @@ export function buildGroupChatContext(params: {

231231

lines.push(`You are in a ${providerLabel} group chat.`);

232232

if (messageToolOnly) {

233233

lines.push(

234-

"Normal final replies are private and are not automatically sent to this group chat. To post visible output here, use the message tool with action=send; the target defaults to this group chat.",

234+

'Normal final replies are private and are not automatically sent to this group chat. If this turn needs visible output here, call the message tool with action="send" before ending; the target defaults to this group chat.',

235235

);

236236

} else {

237237

lines.push(

@@ -255,7 +255,7 @@ export function buildGroupChatContext(params: {

255255

!messageToolOnly && params.silentToken && params.silentReplyPolicy !== "disallow";

256256

if (messageToolOnly) {

257257

lines.push(

258-

"If no visible group response is needed, do not call message(action=send). Your normal final answer stays private and will not be posted to the group.",

258+

'If no visible group response is needed, do not call message(action="send"). Your normal final answer stays private and will not be posted to the group.',

259259

);

260260

}

261261

if (canUseSilentReply) {

@@ -286,10 +286,10 @@ export function buildDirectChatContext(params: {

286286

lines.push(`You are in a ${providerLabel} direct conversation.`);

287287

if (messageToolOnly) {

288288

lines.push(

289-

"Normal final replies are private and are not automatically sent to this conversation. To post visible output here, use the message tool with action=send; the target defaults to this conversation.",

289+

'Normal final replies are private and are not automatically sent to this conversation. If this turn needs visible output here, call the message tool with action="send" before ending; the target defaults to this conversation.',

290290

);

291291

lines.push(

292-

"If no visible direct response is needed, do not call message(action=send). Your normal final answer stays private and will not be posted to the conversation.",

292+

'If no visible direct response is needed, do not call message(action="send"). Your normal final answer stays private and will not be posted to the conversation.',

293293

);

294294

return lines.join(" ");

295295

}

Original file line numberDiff line numberDiff line change

@@ -300,7 +300,9 @@ describe("buildInboundUserContextPrefix", () => {

300300

{ sourceReplyDeliveryMode: "message_tool_only" },

301301

);

302302
303-

expect(text).toContain("Delivery: to send a message, use the `message` tool.");

303+

expect(text).toContain(

304+

'Delivery: if this turn needs visible output in the current source conversation, call `message` with `action="send"` before ending.',

305+

);

304306

expect(text.indexOf("Delivery:")).toBeLessThan(text.indexOf("Conversation info"));

305307

expect(text).toContain("Conversation info (untrusted metadata):");

306308

});

@@ -317,7 +319,7 @@ describe("buildInboundUserContextPrefix", () => {

317319

{ sourceReplyDeliveryMode: "automatic" },

318320

);

319321
320-

expect(text).not.toContain("Delivery: to send a message");

322+

expect(text).not.toContain("Delivery: if this turn needs visible output");

321323

expect(text).toContain("Conversation info (untrusted metadata):");

322324

});

323325