Skip to content

ACP/Zed: task tool crashes with 'this.isRunning is not a function' and todo_pause does not stop the continuation loop #2653

Description

@acoliver

Summary

Two bugs manifest exclusively in ACP/Zed mode (not in the interactive CLI), causing the task tool to crash and the todo_pause tool to fail to stop the agent continuation loop.

Bug 1: this.isRunning is not a function when the task tool is invoked

Error:

{"type":"tool_response","callId":"call_CAQhiZPfNrzC3aT0QHXZt0ag","toolName":"task","result":{"error":"this.isRunning is not a function. (In 'this.isRunning()', 'this.isRunning' is undefined)"}}

Root cause: In packages/agents/src/core/subagentExecution.ts, the initInteractiveScheduler() function creates a facade object that copies the scheduler's schedule method without binding it:

return {
  scheduler: {
    schedule: scheduler.schedule,  // ← receiver lost!
    awaitCompletedCalls: channel.awaitCompletedCalls,
  },
  ...
};

When scheduler.schedule() is later called through the facade, JavaScript sets this to the facade object, not the original CoreToolScheduler. The facade has no isRunning() method, so CoreToolScheduler.schedule() crashes when it calls this.isRunning().

Why only in ACP/Zed: The interactive CLI registers its own schedulerFactoryProvider via interactiveToolScheduler.ts, which correctly uses a closure ((req, sig) => instance.schedule(req, sig)). ACP/Zed does not register a scheduler factory, so the fallback path through initInteractiveScheduler() is taken — exposing the unbound method.

Fix: Replace schedule: scheduler.schedule with schedule: (req, sig) => scheduler.schedule(req, sig) in subagentExecution.ts.

Bug 2: todo_pause does not stop the continuation loop

Symptom: When the model calls todo_pause, the agent continues looping instead of stopping. In the CLI this works because the React UI layer has a separate continuation gate (useTodoContinuation.ts) that checks todoPaused. ACP/Zed has no such outer gate.

Root cause: AgenticLoop.buildNextMessage() unconditionally returns continueLoop: true for any successful tool — including todo_pause:

// AgenticLoop.ts — buildNextMessage()
const responseParts = buildToolResponses(agentTools);
if (responseParts.length === 0) {
  return { continueLoop: false, nextMessage: [] };
}
return { continueLoop: true, nextMessage: responseParts };  // ← always continues

There is no check for todo_pause being among the completed tools. The MessageStreamOrchestrator's todoPauseSeen logic is correct but it only observes events from Turn.run(), which emits ToolCallRequest (not ToolCallResponse) for model tool blocks. The actual tool responses are produced later by the AgenticLoop scheduler, which never checks for todo_pause.

Reproduction evidence: Running scripts/test-acp-zed-bugs.mjs confirms the todo_pause scenario times out (the loop never completes), while a normal prompt completes successfully.

Fix: In AgenticLoop.buildNextMessage(), detect a successful todo_pause among the completed tools and return continueLoop: false. Also eagerly record the tool history (via recordCompletedToolHistory from loopHelpers.ts) since there won't be a next model turn to carry the response.

Reproduction

A cross-platform test script has been added at scripts/test-acp-zed-bugs.mjs:

node scripts/test-acp-zed-bugs.mjs --profile <profile-name>

It spawns the llxprt-code process in --experimental-acp mode, performs the ACP handshake, and sends prompts designed to trigger both bugs. Works on Windows, macOS, and Linux.

Impact

  • The task tool is completely unusable in Zed/ACP mode
  • The todo_pause tool (used for loop-breaking) is non-functional in Zed/ACP mode, causing infinite loops and wasted tokens
  • These are core agent loop features that should work identically across all frontends

Metadata

Metadata

Assignees

Labels

IDE IntegrationVSCode/Zed integration issues etc.LoopbreakerIssues that break the loop and cause the model to stop and return to the prompt.acpAgent Client Protocol (ACP) integration and Zed editor supportbugplanPlanning work / issue-planner output

Type

No type

Projects

Status
Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions