diff --git a/bun.lock b/bun.lock index ec32839..c9f96e6 100644 --- a/bun.lock +++ b/bun.lock @@ -8,6 +8,7 @@ "@anthropic-ai/claude-agent-sdk": "^0.2.25", "glob": "^13.0.0", "hono": "^4.11.4", + "p-queue": "^8.0.1", }, "devDependencies": { "@types/bun": "^1.2.21", @@ -59,6 +60,8 @@ "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + "glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], "hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="], @@ -69,6 +72,10 @@ "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="], + + "p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="], + "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], diff --git a/package.json b/package.json index eab0e3a..1e576be 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.2.25", "glob": "^13.0.0", - "hono": "^4.11.4" + "hono": "^4.11.4", + "p-queue": "^8.0.1" }, "devDependencies": { "@types/bun": "^1.2.21", diff --git a/src/proxy/server.ts b/src/proxy/server.ts index b817a86..a45259b 100644 --- a/src/proxy/server.ts +++ b/src/proxy/server.ts @@ -1,6 +1,7 @@ import { Hono } from "hono" import { cors } from "hono/cors" import { query } from "@anthropic-ai/claude-agent-sdk" +import PQueue from "p-queue" import type { Context } from "hono" import type { ProxyConfig } from "./types" import { DEFAULT_PROXY_CONFIG } from "./types" @@ -28,6 +29,9 @@ const ALLOWED_MCP_TOOLS = [ `mcp__${MCP_SERVER_NAME}__grep` ] +// Queue to serialize Claude Agent SDK queries and avoid ~60s delay on concurrent requests +const requestQueue = new PQueue({ concurrency: 1 }) + function resolveClaudeExecutable(): string { // 1. Try the SDK's bundled cli.js (same dir as this module's SDK) try { @@ -256,8 +260,8 @@ export function createProxyServer(config: Partial = {}) { } } - app.post("/v1/messages", handleMessages) - app.post("/messages", handleMessages) + app.post("/v1/messages", (c) => requestQueue.add(() => handleMessages(c))) + app.post("/messages", (c) => requestQueue.add(() => handleMessages(c))) return { app, config: finalConfig } }