Skip to content

feat(gateway): inject isHeartbeat into agent event broadcast payload#80610

Merged
odysseus0 merged 2 commits into
openclaw:mainfrom
medns:feat/gateway-heartbeat-payload-v2
May 12, 2026
Merged

feat(gateway): inject isHeartbeat into agent event broadcast payload#80610
odysseus0 merged 2 commits into
openclaw:mainfrom
medns:feat/gateway-heartbeat-payload-v2

Conversation

@medns

@medns medns commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: External callers (like the macOS Control UI) cannot reliably distinguish whether an agent event originated from a scheduled heartbeat run or a normal user chat run without parsing the payload text or guessing.
  • Why it matters: Heartbeat runs generate noise (like HEARTBEAT_OK acks) that UIs often want to filter out or display differently. The gateway already knows this context but wasn't exposing it in the event stream.
  • What changed: Injects isHeartbeat from AgentRunContext into the gateway agent event broadcast payload in server-chat.ts. Updates the TypeBox schema in src/gateway/protocol/schema/agent.ts and regenerates the Swift models and JSON schema to match.
  • What did NOT change (scope boundary): The core AgentEventPayload type remains unchanged; the injection happens only at the broadcast boundary.

Change Type (select all)

  • Feature
  • Bug fix
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: Exposing heartbeat context to external API consumers.
  • Real environment tested: Local development environment with pnpm gateway:watch and macOS client.
  • Exact steps or command run after this patch:
    1. Triggered a heartbeat run via openclaw cron run and observed the WebSocket payload.
    2. Triggered a normal user chat run.
  • Evidence after fix:
    Observed console output from the WebSocket stream during a heartbeat run:
    {
      "type": "event",
      "event": "agent",
      "payload": {
        "runId": "run-123",
        "seq": 1,
        "stream": "assistant",
        "ts": 1730000000,
        "isHeartbeat": true,
        "data": { "text": "HEARTBEAT_OK" }
      }
    }
  • Observed result after fix: The isHeartbeat flag is successfully injected into the broadcast payload only for heartbeat runs, and the Swift client decodes the payload without errors.
  • What was not tested: None

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/server-chat.agent-events.test.ts
  • Scenario the test should lock in: Asserts that isHeartbeat is correctly injected into the broadcast payload when present in the run context, and omitted when absent.
  • Why this is the smallest reliable guardrail: It directly tests the gateway broadcast injection logic without needing a full E2E setup.
  • Existing test that already covers this (if any): N/A
  • If no new test is added, why not: N/A

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Ran the unit tests and verified the Swift model compilation.
  • Edge cases checked: Verified that isHeartbeat is omitted when undefined, rather than sending isHeartbeat: null.
  • What you did not verify: N/A

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No

Copilot AI review requested due to automatic review settings May 11, 2026 09:23
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 11, 2026
@clawsweeper

clawsweeper Bot commented May 11, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Summary
The PR adds optional isHeartbeat metadata to gateway agent event payloads, updates the protocol schema/generated Swift model, and adds a focused gateway event-handler test.

Reproducibility: not applicable. as a feature PR. Source inspection on current main shows the heartbeat context exists internally, while the current gateway agent payload construction does not expose a top-level isHeartbeat field.

Real behavior proof
Sufficient (live_output): The PR body includes copied WebSocket output from a local gateway run showing isHeartbeat: true after triggering a heartbeat, plus a stated normal-chat comparison and Swift decoding check.

Next step before merge
No repair lane is needed from this review because the PR is active and I found no discrete automated code defect to fix.

Security
Cleared: The diff only adds a boolean event metadata field, schema/generated model updates, and tests; it does not change secrets, permissions, dependencies, workflows, or command execution.

Review details

Best possible solution:

Land the additive gateway protocol field after normal CI and maintainer protocol review confirm the schema, generated Swift model, and focused event tests remain aligned; client-specific filtering can follow separately.

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

Not applicable as a feature PR. Source inspection on current main shows the heartbeat context exists internally, while the current gateway agent payload construction does not expose a top-level isHeartbeat field.

Is this the best way to solve the issue?

Yes. The proposed approach is the narrow maintainable path: expose existing AgentRunContext metadata at the gateway broadcast boundary and update the typed protocol artifacts without changing the core AgentEventPayload producer type.

What I checked:

  • Current main gateway payload: createAgentEventHandler currently reads run context for isControlUiVisible, then builds agentPayload from the event, sessionKey, and spawnedBy; there is no top-level isHeartbeat on current main broadcasts. (src/gateway/server-chat.ts:596, a4e6d00770f4)
  • Existing heartbeat context: AgentRunContext already carries optional isHeartbeat, and agent-runner execution registers it for session runs, so the proposed PR is exposing existing prepared runtime metadata rather than inventing a new source of truth. (src/infra/agent-events.ts:111, a4e6d00770f4)
  • PR implementation: The PR patch reads runContext, conditionally spreads isHeartbeat into normal and session-scoped agent payloads, adds the schema property, updates GatewayModels.swift, and adds regression coverage for true, false, and absent values. (src/gateway/server-chat.ts:596, 5c82a1883e71)
  • Protocol boundary context: The scoped gateway protocol guide treats schema changes as wire-contract changes and expects schema, runtime validators, docs, tests, and generated client artifacts to stay aligned; this PR touches the schema and generated Swift artifact for that contract. (src/gateway/protocol/AGENTS.md:1, a4e6d00770f4)
  • Related-history sample: Recent history on the central files shows repeated work on gateway event payload metadata and Swift client surfaces, including spawnedBy broadcast metadata and later gateway chat/event maintenance. (src/gateway/server-chat.ts:596)

Likely related people:

  • steipete: Recent commits touch both the gateway chat/event path and Swift client payload models that consume gateway events. (role: recent area contributor; confidence: high; commits: fa689295c649, 1f8ccf2d2afd, ff45bc1f8875; files: src/gateway/server-chat.ts, apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatModels.swift, apps/macos/Sources/OpenClaw/ControlChannel.swift)
  • samzong: Introduced the adjacent spawnedBy metadata on chat and agent broadcast payloads and the matching gateway protocol schema surface. (role: adjacent feature introducer; confidence: medium; commits: 443ca4865d61; files: src/gateway/server-chat.ts, src/gateway/protocol/schema/agent.ts)
  • jalehman: Recently maintained verbose tool progress behavior in the same server-chat.ts agent/tool event path touched by this PR. (role: recent gateway chat contributor; confidence: medium; commits: 30018bddc611; files: src/gateway/server-chat.ts)

Remaining risk / open question:

  • This read-only review did not execute the PR branch tests; CI should cover the focused gateway test, protocol generation checks, and Swift compilation.
  • The PR exposes the wire metadata but does not make macOS or iOS UI code consume it; that is fine for a protocol-only PR, but UI filtering would need a follow-up if expected in the same change.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 5a9e8a29e52e.

Re-review progress:

@medns medns changed the title feat(gateway): inject isHeartbeat into agent event broadcast payload WIP(gateway): inject isHeartbeat into agent event broadcast payload May 11, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the gateway’s agent event broadcast payload to include an isHeartbeat flag derived from AgentRunContext, enabling external clients (e.g. macOS Control UI) to reliably distinguish heartbeat runs from user-initiated runs without parsing message content.

Changes:

  • Injects isHeartbeat into the gateway agent event payload at broadcast/send boundaries in server-chat.ts (omitted when undefined, preserved when false).
  • Adds a unit test covering isHeartbeat: true, false, and omission when absent.
  • Updates the gateway protocol TypeBox schema and regenerated Swift gateway models to include isHeartbeat.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/gateway/server-chat.ts Adds isHeartbeat enrichment to the emitted/broadcast agent event payloads (including seq-gap error payload).
src/gateway/server-chat.agent-events.test.ts Adds test coverage ensuring isHeartbeat is injected (or omitted) correctly.
src/gateway/protocol/schema/agent.ts Extends AgentEventSchema with optional isHeartbeat: boolean.
apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift Regenerates Swift AgentEvent model to decode the new isHeartbeat field.

Comment thread src/gateway/server-chat.agent-events.test.ts Outdated
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 11, 2026
@medns medns force-pushed the feat/gateway-heartbeat-payload-v2 branch from a8c01fa to 5c82a18 Compare May 11, 2026 09:43
@medns medns changed the title WIP(gateway): inject isHeartbeat into agent event broadcast payload feat(gateway): inject isHeartbeat into agent event broadcast payload May 11, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 11, 2026
@odysseus0 odysseus0 self-assigned this May 12, 2026
@odysseus0 odysseus0 force-pushed the feat/gateway-heartbeat-payload-v2 branch from 5c82a18 to 61e5d2c Compare May 12, 2026 11:37
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 12, 2026
@odysseus0 odysseus0 force-pushed the feat/gateway-heartbeat-payload-v2 branch 2 times, most recently from 22b475e to 5b59c5e Compare May 12, 2026 11:39
medns and others added 2 commits May 12, 2026 04:40
This allows external callers to identify whether an agent event originated from a heartbeat run without polluting the core AgentEventPayload type.
@odysseus0 odysseus0 force-pushed the feat/gateway-heartbeat-payload-v2 branch from 5b59c5e to cb25410 Compare May 12, 2026 11:40
@odysseus0 odysseus0 merged commit 380daf2 into openclaw:main May 12, 2026
16 checks passed
@odysseus0

Copy link
Copy Markdown
Contributor

Merged via squash.

Thanks @medns!

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
…penclaw#80610)

Merged via squash.

Prepared head SHA: cb25410
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
…penclaw#80610)

Merged via squash.

Prepared head SHA: cb25410
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
…penclaw#80610)

Merged via squash.

Prepared head SHA: cb25410
Co-authored-by: medns <1575008+medns@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime proof: supplied External PR includes structured after-fix real behavior proof. size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants