Skip to content

Commit 0e4d28a

Browse files
VishalJ99steipete
andauthored
fix(codex): force message tool for source replies (#76663)
* fix(codex): force message tool for source replies * docs: credit codex source reply fix (#76663) (thanks @VishalJ99) --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent ffdc76b commit 0e4d28a

3 files changed

Lines changed: 33 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Docs: https://docs.openclaw.ai
5151
- Chat delivery: make `/verbose on|full|off` changes affect subsequent tool-use chat bubbles again, including channels with draft preview tool progress enabled, while preserving one-shot verbose directives.
5252
- CLI/logs: auto-reconnect `openclaw logs --follow` on transient gateway disconnects (WebSocket close, timeout, connection drop) with bounded exponential backoff (up to 8 retries, capped at 30 s) and stderr retry warnings, while still exiting immediately on non-recoverable auth or configuration errors. Fixes #74782. (#75059) Thanks @shashank-poola.
5353
- CLI/logs: announce `--follow` recovery with a `[logs] gateway reconnected` notice once a poll succeeds after a transient outage, and emit JSON `notice` records in `--json` mode for both the retry warning and the reconnect transition, so live monitoring scripts can react to the recovery. Carries forward #75059. (#75372) Thanks @romneyda.
54+
- Codex/WhatsApp: keep the `message` dynamic tool available when Codex source replies are configured for message-tool delivery, so coding-profile chat agents do not complete turns privately without a visible channel reply. Fixes #76660. (#76663) Thanks @VishalJ99.
5455
- Plugins/onboarding: trust optional official plugin and web-search installs selected from the official catalog so npm security scanning treats them like other source-linked official install paths. Thanks @vincentkoc.
5556
- Agents/web_search: keep installed runtime provider discovery enabled when web-search metadata is missing, so externally installed official providers such as Brave remain visible to agent and cron turns instead of falling back to bundled-only lookup. Fixes #76626. Thanks @amknight.
5657
- Tests/plugins: expose the Discord npm onboarding Docker lane as a package script and assert planned Docker lanes point at real scripts, so external-channel onboarding coverage can actually run. Thanks @vincentkoc.

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,37 @@ describe("runCodexAppServerAttempt", () => {
440440
);
441441
});
442442

443+
it("forces the message dynamic tool for message-tool-only source replies", async () => {
444+
const harness = createStartedThreadHarness();
445+
const params = createParams(
446+
path.join(tempDir, "session.jsonl"),
447+
path.join(tempDir, "workspace"),
448+
);
449+
params.disableTools = false;
450+
params.config = { tools: { profile: "coding" } };
451+
params.sourceReplyDeliveryMode = "message_tool_only";
452+
params.messageProvider = "whatsapp";
453+
params.timeoutMs = 60_000;
454+
455+
const run = runCodexAppServerAttempt(params, { turnCompletionIdleTimeoutMs: 5 });
456+
await harness.waitForMethod("thread/start");
457+
await harness.waitForMethod("turn/start");
458+
459+
const startRequest = harness.requests.find((request) => request.method === "thread/start");
460+
const dynamicToolNames = (
461+
(startRequest?.params as { dynamicTools?: Array<{ name: string }> } | undefined)
462+
?.dynamicTools ?? []
463+
).map((tool) => tool.name);
464+
expect(dynamicToolNames).toContain("message");
465+
466+
await new Promise<void>((resolve) => setImmediate(resolve));
467+
await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
468+
await expect(run).resolves.toMatchObject({
469+
timedOut: false,
470+
aborted: false,
471+
});
472+
});
473+
443474
it("returns a failed dynamic tool response when an app-server tool call exceeds the deadline", async () => {
444475
vi.useFakeTimers();
445476
let capturedSignal: AbortSignal | undefined;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,7 @@ async function buildDynamicTools(input: DynamicToolBuildParams) {
14821482
requireExplicitMessageTarget:
14831483
params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
14841484
disableMessageTool: params.disableMessageTool,
1485+
forceMessageTool: params.sourceReplyDeliveryMode === "message_tool_only",
14851486
enableHeartbeatTool: params.trigger === "heartbeat",
14861487
forceHeartbeatTool: params.trigger === "heartbeat",
14871488
onYield: (message) => {

0 commit comments

Comments
 (0)