ACP: session rejects a new prompt as busy after answering the cancelled prompt with 'cancelled'
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 53/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- javascript, node.js, typescript
- Lĩnh vực
- backend-api-design, cli
Hướng nghiên cứu
Start at the mcode acp session prompt and cancellation handling, then trace how an in-flight bash tool call is torn down and when the session's active-turn state is cleared. Compare the tool-call reproduction with the control run without a tool call in flight. Add or locate a regression test for sending a prompt immediately after a cancelled response; done when that prompt is accepted without waiting for a delay.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Product or interface
CLI — ACP (mcode acp), version 0.7.1 (macOS arm64)
Use case and problem
An ACP client that cancels a prompt turn and then sends a new prompt on the same session gets the new prompt rejected as busy, even though the agent already answered the cancelled prompt with stopReason: "cancelled".
Sequence that reproduces it:
session/promptstarts a turn that runs a bash tool call (sleep 45).- While the tool call is
in_progress, the client sendssession/cancel. - The agent answers the original
session/promptwithstopReason: "cancelled"(~40 ms later). - The client immediately sends another
session/prompton the same session. - The agent rejects it:
Internal error: MiniMax Code Runtime failed: Session already has an active Turn. Use queue send to deliver the message after it.
code: -32603
Sending the same prompt ~110 ms later succeeds.
Expected: once the agent has answered the cancelled prompt with the cancelled stop reason, the completed turn no longer prevents a new prompt on that session. Per the ACP cancellation spec the response marks "Agent completes prompt cancellation", so a client that waits for that response — as the spec explicitly allows — still cannot use the session.
Reproduction
Raw log (timestamps relative to process start, mcode acp over stdio via @agentclientprotocol/sdk 0.17.1):
[ 8707ms] tool_call: bash
[ 8808ms] tool call is running - cancelling
[ 10312ms] session/cancel sent (returned after 2 ms - it is a notification)
[ 10351ms] prompt#1: stopReason=cancelled after 41 ms
[ 10357ms] prompt#2 (sent 0ms after the cancelled answer): ERROR -32603 Internal error: MiniMax Code Runtime failed: Session already has an active Turn. Use queue send to deliver the message after it. after 6 ms
[ 10412ms] update: session_info_update {"updatedAt":"2026-10-30T15:39:56.835Z","sessionUpdate":"session_info_update"}
[ 10676ms] update: session_info_update {"updatedAt":"2026-10-30T15:39:57.099Z","sessionUpdate":"session_info_update"}
[ 11293ms] update: session_info_update {"updatedAt":"2026-10-30T15:39:57.715Z","sessionUpdate":"session_info_update"}
[ 11299ms] update: usage_update {"cost":{"amount":0,"currency":"USD"},"size":512000,"used":16743,"sessionUpdate":"usage_update"}
[ 11302ms] update: usage_update {"cost":{"amount":0,"currency":"USD"},"size":512000,"used":16743,"sessionUpdate":"usage_update"}
[ 11302ms] prompt#2 (sent 109ms after the cancelled answer): OK stopReason=end_turn after 842 ms
[ 12334ms] prompt#2 (sent 1253ms after the cancelled answer): OK stopReason=end_turn after 730 ms
[ 14017ms] prompt#2 (sent 2985ms after the cancelled answer): OK stopReason=end_turn after 681 ms
Control run without a tool call in flight — there the next prompt succeeds immediately after the cancelled answer, so the problem is tied to the tool call being torn down:
[ 7931ms] session/cancel sent (returned after 0 ms - it is a notification)
[ 8204ms] prompt#1 answered: {"stopReason":"cancelled"} after 273 ms
[ 10731ms] prompt#2: OK ({"stopReason":"end_turn"}) after 2527 ms
Note also that no terminal tool_call_update is emitted for the cancelled tool call — the only signal that the turn ended is the cancelled answer to the prompt.
Reproduction script
#!/usr/bin/env node
// Repro: mcode acp rejects the next prompt as busy even AFTER it answered the
// cancelled prompt with stopReason: "cancelled".
import { spawn } from "node:child_process";
import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
import { Writable, Readable } from "node:stream";
const t0 = Date.now();
const ts = () => String(Date.now() - t0).padStart(6, " ");
const log = (...a) => console.log(`[${ts()}ms]`, ...a);
const child = spawn("mcode", ["acp"], { stdio: ["pipe", "pipe", "pipe"] });
child.stderr.on("data", (d) => process.env.DEBUG_ACP && log("stderr:", d.toString().trim()));
const stream = ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
let toolStarted = false;
const client = {
sessionUpdate: async (params) => {
const u = params.update ?? {};
if (u.sessionUpdate === "tool_call") {
toolStarted = true;
log("tool_call:", u.title ?? u.toolCallId);
return;
}
if (u.sessionUpdate === "tool_call_update") {
if (u.status === "in_progress") log("tool_call_update in_progress:", u.title ?? "");
return;
}
if (u.sessionUpdate === "agent_message_chunk") return;
log("update:", u.sessionUpdate, JSON.stringify(u).slice(0, 200));
},
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
};
const conn = new ClientSideConnection(() => client, stream);
await conn.initialize({ protocolVersion: 1, clientCapabilities: { fs: {} } });
const { sessionId } = await conn.newSession({ cwd: process.cwd(), mcpServers: [] });
log("session:", sessionId);
const prompt1 = conn
.prompt({
sessionId,
messageId: "m1",
prompt: [{ type: "text", text: "Выполни в bash команду `sleep 45` и дождись её завершения." }],
})
.then((r) => ({ ok: true, r }), (e) => ({ ok: false, e }));
const deadline = Date.now() + 30000;
while (!toolStarted && Date.now() < deadline) await new Promise((r) => setTimeout(r, 100));
log(toolStarted ? "tool call is running - cancelling" : "tool call did not start - cancelling anyway");
await new Promise((r) => setTimeout(r, 1500));
const tCancel = Date.now();
await conn.cancel({ sessionId });
log("session/cancel sent (returned after", Date.now() - tCancel, "ms - it is a notification)");
const res1 = await prompt1;
const tResponse = Date.now();
log(
"prompt#1:",
res1.ok ? `stopReason=${res1.r.stopReason}` : `ERROR ${res1.e?.code} ${String(res1.e?.message).slice(0, 150)}`,
"after",
tResponse - tCancel,
"ms",
);
for (const waitMs of [0, 100, 300, 1000]) {
if (waitMs) await new Promise((r) => setTimeout(r, waitMs));
const sentAt = Date.now();
const res = await conn
.prompt({
sessionId,
messageId: `m2-${waitMs}`,
prompt: [{ type: "text", text: "Reply with one word: ok" }],
})
.then((r) => ({ ok: true, r }), (e) => ({ ok: false, e }));
log(
`prompt#2 (sent ${sentAt - tResponse}ms after the cancelled answer): ${
res.ok
? `OK stopReason=${res.r.stopReason}`
: `ERROR ${res.e?.code} ${String(res.e?.message).slice(0, 180)}`
}`,
"after",
Date.now() - sentAt,
"ms",
);
}
child.kill("SIGTERM");
process.exit(0);
Additional context
This is the provider side of a busy-session problem reported against the Paseo ACP client: https://github.com/getpaseo/paseo/issues/3964
The related request to queue prompts for a busy session instead of rejecting them is #567.
- Ngôn ngữ chính
- TypeScript
- Star
- 2.1k
- Fork
- 271
- Merge trung bình
- 16 giờ 32 phút
- Pull request đã merge (30 ngày)
- 32
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của MiniMax-AI/minimax-code
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
MiniMax-AI/minimax-code#556 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
MiniMax-AI/minimax-code#507 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug needs-triage tui
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
MiniMax-AI/minimax-code#481 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug cli documentation needs-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
MiniMax-AI/minimax-code#299 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 Dưới một giờ Mức phù hợp với người mới 20/100
MiniMax-AI/minimax-code#580 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của MiniMax-AI/minimax-code
Issue tương tự
-
Add API: BlockVectra Data APIĐang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 74/100
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
remotion-dev/remotion#12905 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
supermomonga/paseo-plugin-zcode-provider#83 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
oxidecomputer/skepsis#102 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
voidzero-dev/void#677 ·
Maintainer thường phản hồi trong vòng 1 ngày