Files
opus-agent/worker/index.js
T
Adriano Dal Pastro df068bc0f8 feat: add GET /api/models endpoint
Returns available Claude models from SDK and the configured default model.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 21:07:12 +00:00

134 lines
3.3 KiB
JavaScript

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}`);
});