Skip to content

ctx.abort() during interactive tool_call confirmation can duplicate abort output and continue pending tool calls #4276

@pahar0

Description

@pahar0

What happened?

When an extension calls ctx.abort() from an interactive tool_call confirmation, I saw two abort lifecycle problems:

  1. With one tool call, Operation aborted was rendered twice. The session JSONL had one aborted toolResult, followed by an extra empty assistant message with stopReason: "aborted".
  2. With two tool calls in the same assistant response, choosing Abort run on the first confirmation did not stop the batch. Pi still continued to the second pending edit confirmation.

This is related to #3830, but it is a different abort path. #3830 fixed duplicated rendering for { block: true, reason }; this repro uses ctx.abort().

Tested/reproduced on Pi 0.74.0.

Steps to reproduce

Use this extension:

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { isToolCallEventType } from "@earendil-works/pi-coding-agent";

export default function ctxAbortToolCallRepro(pi: ExtensionAPI) {
        pi.on("tool_call", async (event, ctx) => {
                if (!isToolCallEventType("edit", event) && !isToolCallEventType("write", event)) return undefined;

                const path = event.input.path;
                if (!ctx.hasUI) {
                        ctx.abort();
                        return undefined;
                }

                const choice = await ctx.ui.select(`Confirm ${event.toolName} ${path}`, ["Allow", "Abort run"]);
                if (choice === "Allow") return undefined;

                ctx.abort();
                return undefined;
        });
}

Problem 1, duplicate abort output:

  1. Ask for one edit, for example edit test.txt and replace one word.
  2. Choose Abort run in the extension UI.
  3. I saw Operation aborted twice. The session JSONL had one aborted toolResult, followed by an extra empty assistant message with stopReason: "aborted".
Image

Problem 2, abort continues pending tool calls:

  1. Create two test files:
printf 'a\n' > abort-edit-a.txt
printf 'b\n' > abort-edit-b.txt
  1. Ask the model:
Call edit twice in one response:
1. edit abort-edit-a.txt: replace "a\n" with "x\n"
2. edit abort-edit-b.txt: replace "b\n" with "y\n"

Use exactly two edit tool calls. No text.
  1. Choose Abort run on the first confirmation.
  2. Pi still continued to the second pending edit confirmation.
Image

Expected behavior

Calling ctx.abort() from a tool_call handler should stop the current agent run. The abort message should be rendered once, and remaining tool calls from the same assistant response should not be confirmed or executed.

Version

0.74.0

Metadata

Metadata

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