feat: add Node.js worker with Claude Code SDK

This commit is contained in:
2026-05-25 18:53:43 +02:00
parent 1e69b1aec2
commit d8d7e1a66f
3 changed files with 133 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
FROM node:20-slim
RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY package.json ./
RUN npm install --production
COPY index.js ./
EXPOSE 3001
CMD ["node", "index.js"]
+109
View File
@@ -0,0 +1,109 @@
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.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 messages = await query({
prompt,
options,
});
const resultText = messages
.filter((m) => m.type === "text")
.map((m) => m.text)
.join("\n");
const conversationId = messages.length > 0 ? messages[0].conversationId : null;
res.json({
success: true,
result: resultText,
session_id: conversationId || 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 messages = await query({
prompt: summaryPrompt,
options: {
model: DEFAULT_MODEL,
systemPrompt:
"You are a summarizer. Respond with only the summary, no preamble.",
allowedTools: [],
},
});
const summaryText = messages
.filter((m) => m.type === "text")
.map((m) => m.text)
.join("\n");
res.json({
success: true,
summary: summaryText.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}`);
});
+10
View File
@@ -0,0 +1,10 @@
{
"name": "opus-agent-worker",
"version": "0.1.0",
"private": true,
"type": "module",
"dependencies": {
"express": "^4.21.0",
"@anthropic-ai/claude-code": "^1.0.0"
}
}