Skip to content

Bug: heartbeat exec-completion prompt references phantom system messages — agent always replies "I don't see the output" #69968

@pagem7632-hcm

Description

@pagem7632-hcm

Summary

When an async exec command completes and triggers a heartbeat, the agent consistently replies with a variant of "I don't see any async command output in the system messages above". This is a bug in buildExecEventPrompt() — the actual exec output is never injected into the prompt.

Code trace

File: src/infra/heartbeat-runner.ts (compiled: dist/heartbeat-runner-CInrztfM.js)

Line 167-169buildExecEventPrompt() returns a static string:

"An async command you ran earlier has completed. The result is shown in the system messages above."

Line 512hasExecCompletion is detected from event text (correct):

const hasExecCompletion = pendingEvents.some(isExecCompletionEvent);

Line 539buildExecEventPrompt() is called with no event data:

prompt: hasExecCompletion ? buildExecEventPrompt({ deliverToUser: params.canRelayToUser }) : ...

The exec event entries are mapped to text at line 510 (pendingEvents) and checked for exec completion at line 512, but the actual event text (which contains the compactOutput) is never passed to buildExecEventPrompt(). The model is told to look at system messages that were never injected.

Reproduction

  1. Run a background exec command via the exec tool with background: true
  2. Wait for heartbeat to fire after the exec completes
  3. Observe agent replies: "I don't see any async command output in the system messages above. Could you share the result?"

Expected behaviour

The exec output should be included inline in the heartbeat prompt, so the agent can actually see and relay it.

Proposed fix

Pass the exec event entries through to buildExecEventPrompt() and include compactOutput inline:

function buildExecEventPrompt(opts: { deliverToUser?: boolean; execEvents?: string[] }) {
  const outputSection = opts.execEvents?.length
    ? `\n\nExec output:\n${opts.execEvents.join("\n")}`
    : "";
  if (!(opts?.deliverToUser ?? true)) {
    return `An async command you ran earlier has completed.${outputSection}\nHandle the result internally. Do not relay it to the user unless explicitly requested.`;
  }
  return `An async command you ran earlier has completed.${outputSection}\nPlease relay the command output to the user in a helpful way. If the command succeeded, share the relevant output. If it failed, explain what went wrong.`;
}

Then at line 539:

hasExecCompletion ? buildExecEventPrompt({
  deliverToUser: params.canRelayToUser,
  execEvents: pendingEvents.filter(isExecCompletionEvent)
}) : ...

Environment

  • OpenClaw: 2026.4.15 (041266a)
  • macOS Darwin 25.3.0 (arm64)
  • Node 24.14.0

Impact

Every exec-completion heartbeat produces a confusing "I don't see the output" reply. Users cannot rely on background exec completion notification via heartbeat.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions