import type { AgentTool } from "@mariozechner/pi-agent-core"; import { fauxAssistantMessage, fauxToolCall } from "@mariozechner/pi-ai"; import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; import { Type } from "@sinclair/typebox"; import { afterEach, describe, expect, it } from "vitest"; import { createHarness, getAssistantTexts, getUserTexts, type Harness } from "../harness.js"; describe("issue #2023 queued slash-command follow-up", () => { const harnesses: Harness[] = []; afterEach(() => { while (harnesses.length > 0) { harnesses.pop()?.cleanup(); } }); it("treats extension-origin queued slash-command follow-ups as raw user text instead of dispatching the command", async () => { let extensionApi: ExtensionAPI | undefined; const commandRuns: string[] = []; let releaseToolExecution: (() => void) | undefined; const toolRelease = new Promise((resolve) => { releaseToolExecution = resolve; }); const waitTool: AgentTool = { name: "wait", label: "Wait", description: "Wait for the test to release execution", parameters: Type.Object({}), execute: async () => { await toolRelease; return { content: [{ type: "text", text: "released" }], details: {}, }; }, }; const harness = await createHarness({ tools: [waitTool], extensionFactories: [ (pi) => { extensionApi = pi; pi.registerCommand("testcmd", { description: "Test command", handler: async (args) => { commandRuns.push(args); }, }); }, ], }); harnesses.push(harness); harness.setResponses([ fauxAssistantMessage(fauxToolCall("wait", {}), { stopReason: "toolUse" }), fauxAssistantMessage("first turn complete"), fauxAssistantMessage("queued follow-up handled by model"), ]); const sawToolStart = new Promise((resolve) => { const unsubscribe = harness.session.subscribe((event) => { if (event.type === "tool_execution_start" && event.toolName === "wait") { unsubscribe(); resolve(); } }); }); const promptPromise = harness.session.prompt("start"); await sawToolStart; await new Promise((resolve) => setTimeout(resolve, 0)); extensionApi?.sendUserMessage("/testcmd queued", { deliverAs: "followUp" }); releaseToolExecution?.(); await promptPromise; expect(commandRuns).toEqual([]); expect(getUserTexts(harness)).toEqual(["start", "/testcmd queued"]); expect(getAssistantTexts(harness)).toContain("queued follow-up handled by model"); }); });