`tool_call:completed` event lost after connection reconnect in `stream-json` mode

# `tool_call:completed` event lost after connection reconnect in `stream-json` mode

**Category**: Support / Bug Reports

**Tags**: cli

## Where does the bug appear (feature/product)?

Cursor CLI (`agent` command with `–output-format stream-json --stream-partial-output`)

## Describe the Bug

When using `–output-format stream-json --stream-partial-output`, if a connection drop occurs (emitting `connection:reconnecting` → `retry:starting` → `retry:resuming` → `connection:reconnected`) while a `tool_call:started` event has already been emitted but its corresponding `tool_call:completed` has not, **the `completed` event is permanently lost** after reconnect.

The CLI resumes from a checkpoint and continues with new `thinking`/`assistant`/`tool_call` events, but never emits the missing `completed` event for the interrupted tool call.

### Observed NDJSON sequence (from real production trace):

```jsonl

// Line 215: tool_call started — read a file

{“type”:“tool_call”,“subtype”:“started”,“call_id”:“tool_5189c71e-ea33-48cf-86d3-a2a3b29422b”,“tool_call”:{“readToolCall”:{“args”:{“path”:“/worker/exec/2/.cursor/skills/run-data-query/scripts/run_data_tools.py”,“offset”:1,“limit”:50}}},“session_id”:“…”,“timestamp_ms”:1776080394435}

// Line 216-219: connection drops and reconnects (~33s later, reconnect takes ~24s)

{“type”:“connection”,“subtype”:“reconnecting”,“session_id”:“…”,“timestamp_ms”:1776080427217}

{“type”:“retry”,“subtype”:“starting”,“session_id”:“…”,“timestamp_ms”:1776080429370,“attempt”:1,“is_resume”:true}

{“type”:“retry”,“subtype”:“resuming”,“session_id”:“…”,“timestamp_ms”:1776080429370,“checkpoint_turn_count”:1,“attempt”:1}

{“type”:“connection”,“subtype”:“reconnected”,“session_id”:“…”,“timestamp_ms”:1776080450937}

// Line 220+: resumes with NEW thinking events — NO tool_call:completed for call_id tool_5189c71e-…

{“type”:“thinking”,“subtype”:“delta”,“text”:“…”,“session_id”:“…”,“timestamp_ms”:1776080475313}

```

**The `tool_call:completed` for `call_id=tool_5189c71e-ea33-48cf-86d3-a2a3b29422b` is never emitted.**

### Impact on consumers

For consumers that track pending tool calls (matching `started` ↔ `completed` by `call_id`):

1. The orphaned `call_id` stays in the pending set forever

2. Any logic gated on “all pending tools completed” (e.g., step boundaries in a ReAct trace) is permanently broken

3. All subsequent tool calls get merged into a single oversized step instead of being properly segmented

In our case, a step that should have contained ~2 tool calls ended up with **11 tool calls** because the orphan prevented step completion.

### Additional issue: undocumented event types

The `connection` and `retry` event types (`reconnecting`, `reconnected`, `starting`, `resuming`) are not documented anywhere in the CLI stream-json specification. Consumers have no way to know these exist or how to handle them.

## Expected Behavior

One of:

1. **Preferred**: After reconnect, re-emit the missing `tool_call:completed` event (with the actual result, since the tool did execute server-side)

2. **Acceptable**: Emit a `tool_call:cancelled` or `tool_call:lost` event so consumers can clean up their pending state

3. **Minimum**: Document the `connection`/`retry` event types and recommend that consumers treat `connection:reconnecting` as an implicit cancellation of all pending `tool_call:started` events

## Steps to Reproduce

1. Run a long Cursor CLI task with `–output-format stream-json --stream-partial-output` that makes many tool calls

2. During execution, cause a network interruption (or wait for a natural connection drop)

3. Observe that the CLI reconnects and resumes, but any in-flight `tool_call:started` events never receive their `completed` counterpart

## Environment

- Cursor CLI version: latest (April 2026)

- Flags: `–output-format stream-json --stream-partial-output --model composer-2`

- OS: Linux

## Related

This is a follow-up to my earlier post about undocumented assistant event forms:

Hi there!

We detected that this may be a bug report, so we’ve moved your post to the Bug Reports category.

To help us investigate and fix this faster, could you edit your original post to include the details from the template below?

Bug Report Template - Click to expand

Where does the bug appear (feature/product)?

  • Cursor IDE
  • Cursor CLI
  • Background Agent (GitHub, Slack, Web, Linear)
  • BugBot
  • Somewhere else…

Describe the Bug
A clear and concise description of what the bug is.


Steps to Reproduce
How can you reproduce this bug? We have a much better chance at fixing issues if we can reproduce them!


Expected Behavior
What is meant to happen here that isn’t working correctly?


Screenshots / Screen Recordings
If applicable, attach images or videos (.jpg, .png, .gif, .mp4, .mov)


Operating System

  • Windows 10/11
  • MacOS
  • Linux

Version Information

  • For Cursor IDE: Menu → About Cursor → Copy
  • For Cursor CLI: Run agent about in your terminal
IDE:
Version: 2.xx.x
VSCode Version: 1.105.1
Commit: ......

CLI:
CLI Version 2026.01.17-d239e66

For AI issues: which model did you use?
Model name (e.g., Sonnet 4, Tab…)


For AI issues: add Request ID with privacy disabled
Request ID: f9a7046a-279b-47e5-ab48-6e8dc12daba1
For Background Agent issues, also post the ID: bc-…


Additional Information
Add any other context about the problem here.


Does this stop you from using Cursor?

  • Yes - Cursor is unusable
  • Sometimes - I can sometimes use Cursor
  • No - Cursor works, but with this issue

The more details you provide, the easier it is for us to reproduce and fix the issue. Thanks!

Hi @weiji,

Thanks for another detailed report, and for the production trace.

This is a confirmed bug. When a connection drop occurs during an in-flight tool call, the reconnect/resume path does not re-emit the missing tool_call:completed event. This means any consumer tracking pending tool calls by call_id will end up with permanently orphaned entries, exactly as you described.

Your proposal #3 (the minimum) is a solid immediate workaround: treat connection:reconnecting as an implicit cancellation of all pending tool_call:started events. That will unblock your step segmentation logic while we work on a proper fix.

We’re tracking this internally, and I’ll follow up when there’s an update. Regarding the undocumented connection/retry event types, you’re right that those are missing from the output format docs. Colin already noted the doc updates from your prior thread, and we’ll make sure these event types are included as well.