Skip to content

Add compact JS heap leak report command #31

Description

@thymikee

Problem

agent-cdp already exposes the primitives needed to identify JavaScript heap leaks:

  • memory usage sample|diff|leak-signal
  • memory snapshot capture|diff|leak-triplet
  • memory snapshot classes|instances|retainers
  • memory allocation start|stop|hotspots

For an agent workflow, the user still has to run several commands and synthesize the final leak finding manually. That works, but it is more verbose than necessary and makes agents choose between multiple partially overlapping commands.

This came up while integrating React Native/Metro CDP support for agent-device: we want agent-device to expose agent-cdp narrowly for JS heap leaks, while keeping React rendering under agent-react-devtools and native/process memory under agent-device perf memory.

Related transport PR: #30

Current output

The existing command outputs are useful individually.

Heap usage sample:

jm_1 (baseline) used:14.17 MB total:20.00 MB gc at 2026-06-25 13:31:01

Heap usage diff:

jm_1 → jm_2: used 14.17 MB→23.88 MB (+9.71 MB +68.53%) total 20.00 MB→32.00 MB (+12.00 MB)

Snapshot diff:

ms_1 → ms_2
~ JSObject(Dictionary)           object             +0          +0 B      +9.71 MB
~ JSArray                        object             +1         +80 B      +9.71 MB
~ (string)                       string         +20002      +7.93 MB      +7.93 MB
+ JSObject(tag, index, payload)  object         +20000      +1.53 MB      +9.46 MB
+ __agentDeviceIntentionalLeak   symbol             +1          +4 B          +4 B

Leak triplet:

ms_1 → ms_2 → ms_3

  JSObject(Dictionary)           object          5.12 MB      14.83 MB      14.83 MB  1.00
  JSArray                        object          3.70 MB      13.41 MB      13.41 MB  1.00
  JSObject(tag, index, payload)  object              0 B       9.46 MB       9.46 MB  1.00

Retainers:

[object] JSArray (id=478047) .[0]
  [object] JSObject(Dictionary) (id=83) .__agentDeviceIntentionalLeak
    [synthetic] (RuntimeFields) (id=13) .[0]
      [synthetic] (GC roots) (id=3) .[4]

These are enough to identify the leak, but an agent has to combine them into a human finding.

Proposed change

Add a compact leak report command that combines the useful pieces into one bounded report.

Possible interface:

agent-cdp memory leak report --baseline ms_1 --action ms_2 --cleanup ms_3 --limit 5

Optional convenience workflow for usage checkpoints:

agent-cdp memory leak signal --baseline jm_1 --action jm_2 --cleanup jm_3

I would keep this under memory leak or memory snapshot leak-report, rather than expanding CPU/profile/trace scope.

Desired output

Default output should be intentionally small and agent-friendly:

JS heap leak signal: high
Snapshots: ms_1 baseline → ms_2 after-action → ms_3 cleanup
Retained heap: 80.05 MB → 89.77 MB → 89.77 MB

Top retained suspects:
1. JSObject(tag, index, payload)
   +20,000 instances, +9.46 MB retained, persistence 1.00
   retained by: globalThis.__agentDeviceIntentionalLeak → GC roots
   confidence: high (growth persisted after cleanup; retaining path found)

2. (string)
   +20,002 instances, +7.93 MB retained, persistence 1.00
   retained by: JSObject(tag, index, payload).payload
   confidence: medium (payload of top suspect)

Next: inspect code writing __agentDeviceIntentionalLeak.

Selection and filtering recommendations

  • Rank suspects by retained delta that persists from action to cleanup.
  • Prefer app-owned names/paths when source/module information is available.
  • Group framework/runtime noise separately: React Native, Hermes/runtime internals, Expo shell, native/synthetic roots.
  • Include the shortest useful retaining path for each suspect, not every retainer.
  • Include confidence/evidence labels such as:
    • heap grew after action
    • growth persisted after cleanup
    • GC was requested
    • retaining path found
    • source/module attribution available
  • Keep raw snapshots and large allocation profiles as artifacts, not terminal output.

Why this matters

For AI agents and CLI users, this would turn a multi-command investigation into a clear diagnosis surface. It also avoids overlap with React DevTools:

  • React/component render problems stay in agent-react-devtools
  • Native/process memory stays in platform tooling
  • agent-cdp becomes the clear owner for JavaScript heap leak evidence

Compatibility

This can be additive. Existing memory usage, memory snapshot, and memory allocation commands do not need to change.

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