node-red-contrib-anthropic
Version:
A Node-RED node that interacts with Anthropic machine learning models to generate text.
126 lines (99 loc) • 4 kB
JavaScript
module.exports = (RED) => {
const { Anthropic } = require("@anthropic-ai/sdk");
const ACCEPT_TOPIC_LIST = [
"opus",
"sonnet",
"haiku",
].map((item) => item.toLowerCase());
const main = function (config) {
const node = this;
RED.nodes.createNode(node, config);
node.on("input", async(msg) => {
const API_KEY = this.credentials.ANTHROPIC_API_KEY || msg.ANTHROPIC_API_KEY;
const configuration = {
apiKey: API_KEY,
};
const anthropicClient = new Anthropic(configuration);
node.status({
fill: "green",
shape: "dot",
text: "Processing...",
});
if (config.topic !== "") {
msg.topic = config.topic;
}
if (msg.topic) {
msg.topic = msg.topic.toLowerCase();
}
if (!ACCEPT_TOPIC_LIST.includes(msg.topic) && msg.topic !== "") {
node.status({
fill: "red",
shape: "dot",
text: "msg.topic is incorrect",
});
node.error(`msg.topic must be a string set to one of the following values: ${ACCEPT_TOPIC_LIST.map((item) => ` '${item}' `).join(", ")}`);
node.send(msg);
} else {
const claudeModel = `claude-3-5-${msg.topic}-20241022`
try {
if (typeof msg.history === "undefined")
msg.history = [];
const input = {
role: "user",
content: msg.payload,
};
msg.history.push(input);
const response = await anthropicClient.messages.create({
model: claudeModel,
max_tokens: parseInt(msg.max_tokens) || 1024,
messages: msg.history,
metadata: msg.metadata,
stop_sequences: msg.stop_sequences || msg.stop || undefined, // for gpt compat
temperature: parseInt(msg.temperature) || 1,
top_p: parseInt(msg.top_p) || 1,
top_k: parseInt(msg.top_k) || undefined,
tools: msg.tools || undefined,
tool_choice: msg.tool_choice || undefined,
system: msg.system || undefined,
stream: msg.stream || false
});
// wont handle differnet content yet
const trimmedContent =
response.content[0].text.trim();
const result = {
role: "assistant",
content: trimmedContent,
};
msg.history.push(result);
msg.payload = result;
msg.full = response;
node.status({
fill: "blue",
shape: "dot",
text: "Response complete",
});
node.send(msg);
} catch (error) {
node.status({
fill: "red",
shape: "dot",
text: "Error",
});
if (error.response) {
node.error(error.response, msg);
} else {
node.error(error.message, msg);
}
}
}
});
node.on("close", () => {
node.status({});
});
};
RED.nodes.registerType("anthropic", main, {
credentials: {
ANTHROPIC_API_KEY: { type: "text" },
},
});
};