From c47346cc6237044ecb60ff22c4011d89744af581 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Fri, 22 May 2026 20:54:19 +0900 Subject: feat: message queue/interrupt system, CORS fix, mobile fixes, chat splitting - Add message queue allowing users to send messages while agent is running - Queue messages are injected into tool results as [USER INTERRUPT] - Retrieve tool interrupted via Promise.race when user message arrives - Queued messages show with 'queued' badge and cancel button - Consumed messages repositioned and chat splits at interrupt point - New assistant message block created after interrupt for clean flow - Add POST /chat/cancel endpoint for cancelling queued messages - Fix CORS to allow any origin (Tailscale/LAN access) - Fix crypto.randomUUID fallback for non-secure contexts (HTTP) - Fix frontend API URL derivation from page hostname - Auto-create DB tab if missing on processMessage (foreign key fix) - Add error logging to processMessage catch block - Fix working directory input sync on agent switch - Fix agent mode button to re-apply agent settings --- packages/api/src/app.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'packages/api/src/app.ts') diff --git a/packages/api/src/app.ts b/packages/api/src/app.ts index 37514c3..53cfb6c 100644 --- a/packages/api/src/app.ts +++ b/packages/api/src/app.ts @@ -16,7 +16,7 @@ export const app = new Hono(); app.use( "*", cors({ - origin: "http://localhost:5173", + origin: (origin) => origin || "*", credentials: true, allowHeaders: ["Content-Type", "Authorization"], allowMethods: ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"], @@ -43,6 +43,7 @@ app.post("/chat", async (c) => { modelId?: unknown; reasoningEffort?: unknown; workingDirectory?: unknown; + queueId?: unknown; }>(); const { tabId, message } = body; @@ -55,7 +56,9 @@ app.post("/chat", async (c) => { } if (agentManager.getTabStatus(tabId) === "running") { - return c.json({ error: "agent is already running for this tab" }, 409); + const queueId = typeof body.queueId === "string" ? body.queueId : undefined; + const { messageId } = agentManager.queueMessage(tabId, message, queueId); + return c.json({ status: "queued", messageId }); } const keyId = typeof body.keyId === "string" ? body.keyId : undefined; @@ -74,6 +77,18 @@ app.post("/chat", async (c) => { }); app.route("/config", configRoutes); + +app.post("/chat/cancel", async (c) => { + const body = await c.req.json(); + if (typeof body.tabId !== "string" || typeof body.messageId !== "string") { + return c.json({ error: "tabId and messageId are required strings" }, 400); + } + const tabId = body.tabId; + const messageId = body.messageId; + const cancelled = agentManager.cancelQueuedMessage(tabId, messageId); + return c.json({ success: cancelled }); +}); + app.route("/skills", skillsRoutes); app.route("/models", modelsRoutes); app.route("/tabs", tabsRoutes); -- cgit v1.2.3