From 18ac639ba18ada1be97916303e526c202c87f376 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Thu, 16 Apr 2026 11:24:42 +0200 Subject: [PATCH 1/2] fix(vscode): avoid stale queued message state --- .changeset/fix-queued-message-state.md | 5 +++ .../tests/unit/session-queue.test.ts | 37 +++++++++++++++++++ .../webview-ui/src/context/session-queue.ts | 3 +- .../webview-ui/src/types/messages.ts | 1 + 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 .changeset/fix-queued-message-state.md create mode 100644 packages/kilo-vscode/tests/unit/session-queue.test.ts diff --git a/.changeset/fix-queued-message-state.md b/.changeset/fix-queued-message-state.md new file mode 100644 index 00000000000..8da3bef4a24 --- /dev/null +++ b/.changeset/fix-queued-message-state.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Fix queued-state detection so prompts sent after a completed response are treated as active instead of queued. diff --git a/packages/kilo-vscode/tests/unit/session-queue.test.ts b/packages/kilo-vscode/tests/unit/session-queue.test.ts new file mode 100644 index 00000000000..71df55fa3a1 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/session-queue.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from "bun:test" +import { activeUserMessageID } from "../../webview-ui/src/context/session-queue" +import type { Message } from "../../webview-ui/src/types/messages" + +const base = { + sessionID: "session", + createdAt: "2026-01-01T00:00:00.000Z", + time: { created: 1 }, +} + +const user = (id: string): Message => ({ ...base, id, role: "user" }) + +const assistant = (id: string, parentID: string, opts: Partial = {}): Message => ({ + ...base, + id, + parentID, + role: "assistant", + ...opts, +}) + +describe("activeUserMessageID", () => { + it("ignores terminal assistant updates without completed timestamps", () => { + const messages = [user("message_1"), assistant("message_2", "message_1", { finish: "stop" }), user("message_3")] + + expect(activeUserMessageID(messages, { type: "busy" })).toBe("message_3") + }) + + it("keeps tool-call assistants active until their follow-up finishes", () => { + const messages = [ + user("message_1"), + assistant("message_2", "message_1", { finish: "tool-calls" }), + user("message_3"), + ] + + expect(activeUserMessageID(messages, { type: "busy" })).toBe("message_1") + }) +}) diff --git a/packages/kilo-vscode/webview-ui/src/context/session-queue.ts b/packages/kilo-vscode/webview-ui/src/context/session-queue.ts index ac64139585b..8a0207bb420 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session-queue.ts +++ b/packages/kilo-vscode/webview-ui/src/context/session-queue.ts @@ -3,18 +3,17 @@ import type { Message, SessionStatusInfo } from "../types/messages" // Find the user message whose turn the server is actively processing. // Any user message after this one is "queued" (waiting for its turn). export function activeUserMessageID(messages: Message[], status: SessionStatusInfo) { - // Walk backward to find a non-completed assistant — its parent is the active turn for (let i = messages.length - 1; i >= 0; i -= 1) { const msg = messages[i] if (msg.role !== "assistant") continue if (typeof msg.time?.completed === "number") continue + if (msg.finish && msg.finish !== "tool-calls") continue if (!msg.parentID) break const parent = messages.find((item) => item.id === msg.parentID) if (parent?.role === "user") return parent.id break } - // No pending assistant found — if busy, the last user message is the active turn if (status.type === "idle") return undefined for (let i = messages.length - 1; i >= 0; i -= 1) { diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index 7a2254bfa5f..c40901cdb59 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -125,6 +125,7 @@ export interface Message { summary?: { title?: string; body?: string; diffs?: unknown[] } | boolean cost?: number tokens?: TokenUsage + finish?: string } // File diff info (matches Snapshot.FileDiff from CLI backend) From 07afbb8c91f958bd2b379d6c3b84f19445f5cd79 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Thu, 16 Apr 2026 11:48:54 +0200 Subject: [PATCH 2/2] fix(vscode): handle unknown queued state --- packages/kilo-vscode/tests/unit/session-queue.test.ts | 6 ++++++ .../kilo-vscode/webview-ui/src/context/session-queue.ts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/kilo-vscode/tests/unit/session-queue.test.ts b/packages/kilo-vscode/tests/unit/session-queue.test.ts index 71df55fa3a1..633d4411b3c 100644 --- a/packages/kilo-vscode/tests/unit/session-queue.test.ts +++ b/packages/kilo-vscode/tests/unit/session-queue.test.ts @@ -34,4 +34,10 @@ describe("activeUserMessageID", () => { expect(activeUserMessageID(messages, { type: "busy" })).toBe("message_1") }) + + it("keeps unknown assistants active until cleanup finishes", () => { + const messages = [user("message_1"), assistant("message_2", "message_1", { finish: "unknown" }), user("message_3")] + + expect(activeUserMessageID(messages, { type: "busy" })).toBe("message_1") + }) }) diff --git a/packages/kilo-vscode/webview-ui/src/context/session-queue.ts b/packages/kilo-vscode/webview-ui/src/context/session-queue.ts index 8a0207bb420..7ae6b63117a 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session-queue.ts +++ b/packages/kilo-vscode/webview-ui/src/context/session-queue.ts @@ -7,7 +7,7 @@ export function activeUserMessageID(messages: Message[], status: SessionStatusIn const msg = messages[i] if (msg.role !== "assistant") continue if (typeof msg.time?.completed === "number") continue - if (msg.finish && msg.finish !== "tool-calls") continue + if (msg.finish && !["tool-calls", "unknown"].includes(msg.finish)) continue if (!msg.parentID) break const parent = messages.find((item) => item.id === msg.parentID) if (parent?.role === "user") return parent.id