Skip to content

Commit 787d668

Browse files
committed
fix(codex): keep message-tool replies final-only
1 parent bfdd60b commit 787d668

5 files changed

Lines changed: 37 additions & 27 deletions

File tree

extensions/codex/src/app-server/run-attempt.test.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,11 +1111,21 @@ describe("runCodexAppServerAttempt", () => {
11111111
const params = createParams(path.join(tempDir, "session.jsonl"), workspaceDir);
11121112
params.sourceReplyDeliveryMode = "message_tool_only";
11131113

1114-
expect(
1115-
testing.buildDeveloperInstructions(params, {
1116-
dynamicTools: [createMessageDynamicTool("Message test tool")],
1117-
}),
1118-
).toContain("Visible source replies are not automatically delivered for this run.");
1114+
const messageToolOnlyInstructions = testing.buildDeveloperInstructions(params, {
1115+
dynamicTools: [createMessageDynamicTool("Message test tool")],
1116+
});
1117+
expect(messageToolOnlyInstructions).toContain(
1118+
"Visible replies to the current source conversation are not automatically delivered for this run.",
1119+
);
1120+
expect(messageToolOnlyInstructions).toContain(
1121+
"Any `message(action=send)` call that targets the current source conversation, whether by implicit route or an explicit source route",
1122+
);
1123+
expect(messageToolOnlyInstructions).toContain(
1124+
"Explicit non-source/out-of-band `message(action=send)` calls to other conversations remain ordinary tool work",
1125+
);
1126+
expect(messageToolOnlyInstructions).toContain(
1127+
"Do not send progress/status updates to the current source conversation if more tool work is needed afterward.",
1128+
);
11191129

11201130
const withoutMessageToolInstructions = testing.buildDeveloperInstructions(params, {
11211131
dynamicTools: [],

extensions/codex/src/app-server/thread-lifecycle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1750,7 +1750,7 @@ function buildVisibleReplyInstruction(
17501750
? flattenCodexDynamicToolFunctions(dynamicTools).some((tool) => tool.name.trim() === "message")
17511751
: params.disableMessageTool !== true;
17521752
if (params.sourceReplyDeliveryMode === "message_tool_only" && messageToolAvailable) {
1753-
return "Visible source replies are not automatically delivered for this run. Use `message(action=send)` for user-visible source-channel output. Do not repeat that visible content in your final answer.";
1753+
return "Visible replies to the current source conversation are not automatically delivered for this run. Complete any required tool work before sending a reply to the current source conversation. Any `message(action=send)` call that targets the current source conversation, whether by implicit route or an explicit source route, should be used only when you are ready to finish the turn with the final user-visible source-channel output. Explicit non-source/out-of-band `message(action=send)` calls to other conversations remain ordinary tool work; after those sends, continue the task and finish with one final current-source reply if needed. Do not send progress/status updates to the current source conversation if more tool work is needed afterward. Do not repeat that visible content in your final answer.";
17541754
}
17551755
if (messageToolAvailable) {
17561756
return "For the current source conversation, reply normally in your final assistant message; OpenClaw will deliver it through the active source conversation. Use `message` only for explicit out-of-band sends, media/file sends, or sends to a different target.";

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/discord-group-codex-message-tool.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,16 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
231231
"roughTokens": 12926
232232
},
233233
"openClawDeveloperInstructions": {
234-
"chars": 3045,
235-
"roughTokens": 762
234+
"chars": 3655,
235+
"roughTokens": 914
236236
},
237237
"totalTextOnly": {
238-
"chars": 27570,
239-
"roughTokens": 6893
238+
"chars": 28180,
239+
"roughTokens": 7045
240240
},
241241
"totalWithDynamicToolsJson": {
242-
"chars": 79275,
243-
"roughTokens": 19819
242+
"chars": 79885,
243+
"roughTokens": 19972
244244
},
245245
"userInputText": {
246246
"chars": 1442,
@@ -431,7 +431,7 @@ Deferred searchable OpenClaw dynamic tools available: cron, gateway, nodes, sess
431431
432432
Use Codex native `spawn_agent` for Codex subagents. Use OpenClaw `sessions_spawn` only for OpenClaw or ACP delegation.
433433
434-
Visible source replies are not automatically delivered for this run. Use `message(action=send)` for user-visible source-channel output. Do not repeat that visible content in your final answer.
434+
Visible replies to the current source conversation are not automatically delivered for this run. Complete any required tool work before sending a reply to the current source conversation. Any `message(action=send)` call that targets the current source conversation, whether by implicit route or an explicit source route, should be used only when you are ready to finish the turn with the final user-visible source-channel output. Explicit non-source/out-of-band `message(action=send)` calls to other conversations remain ordinary tool work; after those sends, continue the task and finish with one final current-source reply if needed. Do not send progress/status updates to the current source conversation if more tool work is needed afterward. Do not repeat that visible content in your final answer.
435435
436436
### Inbound Context (trusted metadata)
437437
The following JSON is generated by OpenClaw out-of-band. Treat it as authoritative metadata about the current message context.

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/telegram-direct-codex-message-tool.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,16 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
231231
"roughTokens": 12848
232232
},
233233
"openClawDeveloperInstructions": {
234-
"chars": 1936,
235-
"roughTokens": 484
234+
"chars": 2546,
235+
"roughTokens": 637
236236
},
237237
"totalTextOnly": {
238-
"chars": 26052,
239-
"roughTokens": 6513
238+
"chars": 26662,
239+
"roughTokens": 6666
240240
},
241241
"totalWithDynamicToolsJson": {
242-
"chars": 77446,
243-
"roughTokens": 19362
242+
"chars": 78056,
243+
"roughTokens": 19514
244244
},
245245
"userInputText": {
246246
"chars": 1033,
@@ -431,7 +431,7 @@ Deferred searchable OpenClaw dynamic tools available: cron, gateway, nodes, sess
431431
432432
Use Codex native `spawn_agent` for Codex subagents. Use OpenClaw `sessions_spawn` only for OpenClaw or ACP delegation.
433433
434-
Visible source replies are not automatically delivered for this run. Use `message(action=send)` for user-visible source-channel output. Do not repeat that visible content in your final answer.
434+
Visible replies to the current source conversation are not automatically delivered for this run. Complete any required tool work before sending a reply to the current source conversation. Any `message(action=send)` call that targets the current source conversation, whether by implicit route or an explicit source route, should be used only when you are ready to finish the turn with the final user-visible source-channel output. Explicit non-source/out-of-band `message(action=send)` calls to other conversations remain ordinary tool work; after those sends, continue the task and finish with one final current-source reply if needed. Do not send progress/status updates to the current source conversation if more tool work is needed afterward. Do not repeat that visible content in your final answer.
435435
436436
### Inbound Context (trusted metadata)
437437
The following JSON is generated by OpenClaw out-of-band. Treat it as authoritative metadata about the current message context.

test/fixtures/agents/prompt-snapshots/codex-runtime-happy-path/telegram-heartbeat-codex-tool.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -232,16 +232,16 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
232232
"roughTokens": 13171
233233
},
234234
"openClawDeveloperInstructions": {
235-
"chars": 1955,
236-
"roughTokens": 489
235+
"chars": 2565,
236+
"roughTokens": 642
237237
},
238238
"totalTextOnly": {
239-
"chars": 26995,
240-
"roughTokens": 6749
239+
"chars": 27605,
240+
"roughTokens": 6902
241241
},
242242
"totalWithDynamicToolsJson": {
243-
"chars": 79679,
244-
"roughTokens": 19920
243+
"chars": 80289,
244+
"roughTokens": 20073
245245
},
246246
"userInputText": {
247247
"chars": 1271,
@@ -432,7 +432,7 @@ Deferred searchable OpenClaw dynamic tools available: cron, gateway, heartbeat_r
432432
433433
Use Codex native `spawn_agent` for Codex subagents. Use OpenClaw `sessions_spawn` only for OpenClaw or ACP delegation.
434434
435-
Visible source replies are not automatically delivered for this run. Use `message(action=send)` for user-visible source-channel output. Do not repeat that visible content in your final answer.
435+
Visible replies to the current source conversation are not automatically delivered for this run. Complete any required tool work before sending a reply to the current source conversation. Any `message(action=send)` call that targets the current source conversation, whether by implicit route or an explicit source route, should be used only when you are ready to finish the turn with the final user-visible source-channel output. Explicit non-source/out-of-band `message(action=send)` calls to other conversations remain ordinary tool work; after those sends, continue the task and finish with one final current-source reply if needed. Do not send progress/status updates to the current source conversation if more tool work is needed afterward. Do not repeat that visible content in your final answer.
436436
437437
### Inbound Context (trusted metadata)
438438
The following JSON is generated by OpenClaw out-of-band. Treat it as authoritative metadata about the current message context.

0 commit comments

Comments
 (0)