import express from "express"; import { query } from "@anthropic-ai/claude-code"; const app = express(); app.use(express.json({ limit: "10mb" })); const PORT = process.env.WORKER_PORT || 3001; const DEFAULT_MODEL = process.env.CLAUDE_MODEL || "claude-sonnet-4-6"; app.get("/health", (_req, res) => { res.json({ status: "ok" }); }); app.get("/models", async (_req, res) => { try { const conv = query({ prompt: ".", options: { model: "claude-sonnet-4-6", allowedTools: [] }, }); const models = await conv.supportedModels(); await conv.return(); res.json({ success: true, models }); } catch (error) { res.json({ success: false, error: error.message }); } }); app.post("/process", async (req, res) => { const { prompt, system_prompt, model, session_id } = req.body; if (!prompt) { return res .status(400) .json({ success: false, error: "prompt is required" }); } try { const options = { model: model || DEFAULT_MODEL, systemPrompt: system_prompt || undefined, allowedTools: [], }; if (session_id) { options.resume = session_id; } const conv = query({ prompt, options }); const messages = []; try { for await (const msg of conv) { messages.push(msg); } } catch (_) { // SDK throws after process exits; messages already collected } const resultMsg = messages.find((m) => m.type === "result"); if (!resultMsg) { return res.json({ success: false, error: "No result received from Claude" }); } if (resultMsg.is_error) { return res.json({ success: false, error: resultMsg.result }); } res.json({ success: true, result: resultMsg.result || "", session_id: resultMsg.session_id || session_id, }); } catch (error) { console.error("Process error:", error.message); res.json({ success: false, error: error.message, }); } }); app.post("/summarize", async (req, res) => { const { exchanges, mode } = req.body; if (!exchanges || exchanges.length === 0) { return res .status(400) .json({ success: false, error: "exchanges is required" }); } const exchangeText = exchanges .map((e, i) => `Exchange ${i + 1}:\nQ: ${e.prompt}\nA: ${e.result}`) .join("\n\n"); const summaryPrompt = mode === "complete" ? `Summarize these exchanges into a comprehensive overview. Be concise but thorough:\n\n${exchangeText}` : `Summarize this exchange in 1-2 sentences:\n\n${exchangeText}`; try { const conv = query({ prompt: summaryPrompt, options: { model: DEFAULT_MODEL, systemPrompt: "You are a summarizer. Respond with only the summary, no preamble.", allowedTools: [], }, }); const msgs = []; try { for await (const msg of conv) { msgs.push(msg); } } catch (_) { // SDK throws after process exits; messages already collected } const resultMsg = msgs.find((m) => m.type === "result"); res.json({ success: true, summary: (resultMsg?.result || "").trim(), }); } catch (error) { console.error("Summarize error:", error.message); res.json({ success: false, error: error.message, }); } }); app.listen(PORT, () => { console.log(`Worker listening on port ${PORT}`); });