openclaw - ✅(Solved) Fix [Feature]: Expose per-run token usage on the WebSocket lifecycle event stream [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#57404Fetched 2026-04-08 01:50:03
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Author
Timeline (top)
subscribed ×2commented ×1cross-referenced ×1unsubscribed ×1

Fix Action

Fixed

PR fix notes

PR #51317: agents: emit lifecycle usage event with accumulated token/cost data

Description (problem / solution / changelog)

Summary

  • Emit a supplementary lifecycle event with phase: "usage" after each agent run completes, containing accumulated token counts (input, output, cacheRead, cacheWrite), model, provider, and run duration
  • Added to both the primary agent-command path (src/agents/agent-command.ts) and the auto-reply/CLI path (src/auto-reply/reply/agent-runner-execution.ts)
  • Only emitted when agentMeta.usage exists (no event for runs that don't report usage)

Motivation

The lifecycle end event currently contains only timing data (startedAt, endedAt, aborted, stopReason). Token/cost metrics collected in agentMeta during the run are persisted to the session store but never surfaced on the WebSocket event stream. This makes it impossible for external observers (dashboards, recorders, monitoring tools) to track per-run resource consumption without RPC access to session transcripts.

The new phase: "usage" event provides this data on the event stream, enabling passive observers to capture token usage without requiring additional API calls.

Event format

{
  "type": "event",
  "event": "agent",
  "payload": {
    "runId": "...",
    "stream": "lifecycle",
    "data": {
      "phase": "usage",
      "provider": "anthropic",
      "model": "claude-sonnet-4-20250514",
      "usage": {
        "input": 1234,
        "output": 567,
        "cacheRead": 890,
        "cacheWrite": 100,
        "total": 2791
      },
      "lastCallUsage": { ... },
      "durationMs": 4521
    }
  }
}

Test plan

  • pnpm build passes
  • pnpm check passes (0 warnings, 0 errors)
  • pnpm test -- src/agents/pi-embedded-runner/usage-reporting.test.ts passes (5/5)
  • Tested locally with a custom recorder service — confirmed usage events arrive on the WebSocket stream after runs complete

  • AI-assisted (Claude Code)
  • Fully tested locally
  • I understand what the code does

🤖 Generated with Claude Code

Changed files

  • src/agents/agent-command.ts (modified, +24/-0)
  • src/auto-reply/reply/agent-runner-execution.ts (modified, +63/-11)
  • src/auto-reply/reply/agent-runner-memory.ts (modified, +23/-2)
  • src/auto-reply/reply/followup-runner.ts (modified, +25/-1)
  • src/cron/isolated-agent/run.ts (modified, +73/-1)
  • src/gateway/server-chat.ts (modified, +44/-1)
  • src/infra/agent-events.lifecycle-usage.test.ts (added, +147/-0)
RAW_BUFFERClick to expand / collapse

Problem

The lifecycle end event contains only timing data (startedAt, endedAt, aborted, stopReason). Token and cost metrics collected in agentMeta during a run are persisted to the session store but never surfaced on the WebSocket event stream. This means external observers (dashboards, monitoring tools, recorders) cannot track per-run resource consumption without polling the session RPC after every run completes.

Proposed Solution

Emit a supplementary lifecycle event with phase: "usage" after each agent run completes. The event would carry:

  • Accumulated token counts (input, output, cacheRead, cacheWrite)
  • Model and provider identifiers
  • Wall-clock duration of the run
  • Last-call usage (for distinguishing retries from fresh calls)

This enables passive WebSocket subscribers to capture token/cost data in real time without additional API calls.

Use Case

I maintain Bridge, a browser-based command station for OpenClaw. It connects via WebSocket to observe agent activity and display session details. Currently Bridge has to reconstruct token usage by parsing session transcripts after the fact. A structured usage event on the lifecycle stream would let it show live cost tracking as runs complete.

Alignment with Project Priorities

The contributing guide lists "token usage and compaction optimization" as a current focus area. This proposal directly supports that by making token consumption visible to the event stream ecosystem.

Existing Implementation

I have a working implementation in PR #51317 that covers all 5 agent run paths:

  • src/agents/agent-command.ts (primary agent command)
  • src/auto-reply/reply/agent-runner-execution.ts (auto-reply execution, 2 sites)
  • src/auto-reply/reply/agent-runner-memory.ts (memory flush runs)
  • src/auto-reply/reply/followup-runner.ts (followup runs)
  • src/cron/isolated-agent/run.ts (cron/isolated runs)

Each emission is guarded (if (agentMeta?.usage)) and wrapped in try/catch so failures are non-fatal. Includes a dedicated test suite.

Happy to adjust the implementation based on maintainer feedback on the event shape or emission strategy.

extent analysis

Fix Plan

To implement the proposed solution, follow these steps:

  • Modify the lifecycle event emission in each of the 5 agent run paths to include a supplementary lifecycle event with phase: "usage" after each agent run completes.
  • Include the required fields in the lifecycle event:
    • Accumulated token counts (input, output, cacheRead, cacheWrite)
    • Model and provider identifiers
    • Wall-clock duration of the run
    • Last-call usage (for distinguishing retries from fresh calls)
  • Ensure the emission is guarded by a check for agentMeta?.usage and wrapped in a try/catch block to prevent fatal failures.

Example code snippet for the lifecycle event emission:

if (agentMeta?.usage) {
  try {
    const usageEvent = {
      phase: 'usage',
      inputTokens: agentMeta.usage.input,
      outputTokens: agentMeta.usage.output,
      cacheReadTokens: agentMeta.usage.cacheRead,
      cacheWriteTokens: agentMeta.usage.cacheWrite,
      modelId: agentMeta.modelId,
      providerId: agentMeta.providerId,
      duration: Date.now() - startedAt,
      lastCallUsage: agentMeta.lastCallUsage,
    };
    // Emit the usage event on the WebSocket event stream
    emitLifecycleEvent(usageEvent);
  } catch (error) {
    // Log the error and continue
    console.error('Error emitting usage event:', error);
  }
}

Verification

To verify that the fix worked, check that the supplementary lifecycle event with phase: "usage" is being emitted correctly after each agent run completes. You can do this by:

  • Subscribing to the WebSocket event stream and checking for the presence of the lifecycle event with phase: "usage"
  • Verifying that the event contains the required fields (accumulated token counts, model and provider identifiers, wall-clock duration, and last-call usage)
  • Checking that the event is being emitted correctly for all 5 agent run paths

Extra Tips

  • Make sure to update the test suite to cover the new lifecycle event emission
  • Consider adding logging or monitoring to track any errors that occur during the emission of the lifecycle event
  • Review the implementation to ensure that it aligns with the project's contributing guide and priorities.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Feature]: Expose per-run token usage on the WebSocket lifecycle event stream [1 pull requests, 1 comments, 2 participants]