Skip to content

Add structured heartbeat responses and Codex tool replies#75765

Merged
pashpashpash merged 3 commits intomainfrom
codex/heartbeat-response-tool
May 1, 2026
Merged

Add structured heartbeat responses and Codex tool replies#75765
pashpashpash merged 3 commits intomainfrom
codex/heartbeat-response-tool

Conversation

@pashpashpash
Copy link
Copy Markdown
Contributor

@pashpashpash pashpashpash commented May 1, 2026

Heartbeat runs have been relying on text conventions like HEARTBEAT_OK to decide whether a background check should stay quiet or notify the user. That works as a fallback, but it is a weak contract for tool-capable harnesses, especially Codex, where the model can make a deliberate structured call instead of encoding control flow in final text.

This adds a heartbeat_respond dynamic tool with explicit outcome, notify, summary, optional notification text, reason, priority, and nextCheck fields. Quiet responses now map to the same no-visible-update behavior as HEARTBEAT_OK, while notifying responses use notificationText when present and preserve the structured response through the Codex and embedded run plumbing.

The PR now also folds in #75745. Codex harness source replies default to the OpenClaw message tool when messages.visibleReplies is unset, so direct chat output in Codex mode follows the same deliberate visible-send model: the agent can finish its Codex turn privately, and it only posts to the channel when it calls message(action="send"). Explicit user config still wins, including messages.visibleReplies: "automatic" for the legacy direct-reply path.

Codex heartbeat turns get the heartbeat tool by default, and heartbeat runs under messages.visibleReplies: "message_tool" also get it through the normal tool policy path. The old text fallback remains in place for older/non-tool runs.

After pushing this branch, I restarted the local Gateway from the branch and waited for the real dev-agent Telegram heartbeat. The next heartbeat ran on Codex thread 019de4a6-f74e-7562-b37d-1601d6b1c329, run 8c21b180-fbc9-4f6f-9c44-0ad2dc0e7691. The OpenClaw trajectory shows the heartbeat prompt included the new instruction to call heartbeat_respond when available, the model then called heartbeat_respond with outcome needs_attention, notify true, priority normal, a concrete summary, and a reason that a time-sensitive travel item was worth surfacing. The tool result recorded successfully, and the model's final assistant text was only NO_REPLY, which means the Telegram notification came from the structured heartbeat response rather than final-text parsing. Pash confirmed receiving that Telegram notification during the test.

I am deliberately redacting the private itinerary and chat target from this public PR body. The local trajectory for session c96b0d01-dbdc-416b-bc4e-199caf45f4c1 has the raw prompt, tool call, tool result, and NO_REPLY completion for the observed heartbeat.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation gateway Gateway runtime agents Agent runtime and tooling extensions: codex size: L maintainer Maintainer-authored PR labels May 1, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

Codex review: needs maintainer review before merge.

What this changes:

The PR adds structured heartbeat_respond handling, propagates heartbeat tool telemetry through Codex and embedded-runner payloads, defaults Codex source replies to message-tool delivery when config is unset, and updates docs, changelog, SDK exports, and focused tests.

Maintainer follow-up before merge:

The PR has the protected maintainer label and no narrow remaining automation repair; the next action is maintainer review or merge after the normal check gates.

Security review:

Security review cleared: No concrete security or supply-chain regression was found in the PR diff.

Review details

Best possible solution:

Land this PR after maintainer approval and normal PR checks, keeping the structured heartbeat tool alongside the existing text fallback and preserving the generic harness delivery-default seam for other runtimes.

Do we have a high-confidence way to reproduce the issue?

Not applicable as a feature PR rather than a bug report. The high-confidence review path is diff inspection: current main lacks the structured heartbeat/Codex delivery behavior, and the PR adds focused schema, runner, and Codex tests for the new paths.

Is this the best way to solve the issue?

Yes. The design keeps core generic through harness delivery defaults, preserves existing heartbeat text fallback behavior, and now uses the repo's flat enum helpers for provider-portable tool schemas.

What I checked:

  • Protected open PR: The provided GitHub context shows this PR is open, not merged, and labeled maintainer, so it should stay open for explicit maintainer handling rather than automated cleanup. (8ba2de82692b)
  • Previous schema blocker addressed: The updated PR diff defines outcome with stringEnum(HEARTBEAT_TOOL_OUTCOMES) and priority with optionalStringEnum(HEARTBEAT_TOOL_PRIORITIES), matching the repo helper that avoids provider-hostile anyOf schemas. (src/agents/tools/heartbeat-response-tool.ts:13, 8ba2de82692b)
  • Current main lacks the new feature: Current main has no heartbeat_respond, HEARTBEAT_RESPONSE_TOOL, HeartbeatToolResponse, deliveryDefaults, or sourceVisibleReplies implementation hits outside existing visible-reply config references, so this PR is not obsolete on main. (13c40668169f)
  • Codex heartbeat tool wiring: The PR enables and forces the heartbeat tool for Codex heartbeat dynamic-tool builds, which matches the PR body's Codex heartbeat behavior. (extensions/codex/src/app-server/run-attempt.ts:1398, 8ba2de82692b)
  • Harness-level delivery default: The PR adds a generic deliveryDefaults.sourceVisibleReplies seam and resolves it only when direct/source visible-reply config is unset, preserving explicit config and avoiding a core hard-coded Codex id. (src/auto-reply/reply/dispatch-from-config.ts:662, 8ba2de82692b)
  • Security-sensitive surface scan: The diff touches TypeScript source, docs, changelog, and generated SDK hash metadata; it does not change workflows, dependencies, lockfiles, package scripts, permissions, or secret-handling code. (8ba2de82692b)

Likely related people:

  • steipete: Recent main history shows repeated work on the Codex dynamic-tool boundary, heartbeat runner behavior, and source visible-reply delivery paths that this PR extends. (role: recent maintainer; confidence: high; commits: 42aaf0c98a7c, 2d1523e573a8, 1c300cec5d80; files: extensions/codex/src/app-server/run-attempt.ts, extensions/codex/src/app-server/dynamic-tools.ts, src/infra/heartbeat-runner.ts)
  • pashpashpash: Beyond this PR, merged history credits pashpashpash on the native-first Codex dynamic-tool work and Codex hook relay work in the same app-server/tool boundary. (role: adjacent Codex contributor; confidence: medium; commits: 42aaf0c98a7c, 3b5dab372ac2; files: extensions/codex/src/app-server/run-attempt.ts, extensions/codex/src/app-server/dynamic-tools.ts)
  • vignesh07: Recent merged work touched heartbeat-runner behavior and commitments flow around the same heartbeat execution path. (role: heartbeat adjacent maintainer; confidence: medium; commits: b277ae3f4c40, 7451415f36d5, 8e4035d09a88; files: src/infra/heartbeat-runner.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 13c40668169f.

@pashpashpash pashpashpash marked this pull request as ready for review May 1, 2026 17:54
@pashpashpash pashpashpash force-pushed the codex/heartbeat-response-tool branch from a9d6285 to e693753 Compare May 1, 2026 18:09
@pashpashpash pashpashpash changed the title Add structured heartbeat responses Add structured heartbeat responses and Codex tool replies May 1, 2026
@pashpashpash
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

🦞🦞
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.

@pashpashpash
Copy link
Copy Markdown
Contributor Author

Addressed the remaining ClawSweeper finding in 8ba2de8269.

heartbeat_respond now uses the repo's flat enum helpers for both outcome and priority, so those tool parameters serialize as plain string enum schemas instead of anyOf. I also added a focused test that asserts the heartbeat tool schema exposes flat enums and does not emit anyOf for those fields.

Proof from the updated branch: focused heartbeat tool/runner tests passed, pnpm lint:core passed, pnpm check:test-types passed, git diff --check passed, and Testbox pnpm check:changed passed in https://github.com/openclaw/openclaw/actions/runs/25226899253.

@clawsweeper re-review

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

🦞🦞
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling docs Improvements or additions to documentation extensions: codex gateway Gateway runtime maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant