n8n-nodes-straico-chat
Version:
Adds a Straico Chat Model to use with n8n AI Agents and Chains.
165 lines (162 loc) • 7.53 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StraicoChatModel = void 0;
const chat_models_1 = require("@langchain/core/language_models/chat_models");
const messages_1 = require("@langchain/core/messages");
class StraicoChatModel extends chat_models_1.BaseChatModel {
constructor(params) {
var _a, _b;
super(params);
this.boundTools = [];
this.apiKey = params.apiKey;
this.baseURL = params.baseURL || 'https://api.straico.com/v0';
this.modelName = params.modelName;
this.temperature = params.temperature;
this.topP = params.topP;
this.maxTokens = params.maxTokens;
this.presencePenalty = params.presencePenalty;
this.frequencyPenalty = params.frequencyPenalty;
this.timeout = (_a = params.timeout) !== null && _a !== void 0 ? _a : 60000;
this.maxRetries = (_b = params.maxRetries) !== null && _b !== void 0 ? _b : 2;
this.callbacks = params.callbacks;
this.onFailedAttempt = params.onFailedAttempt;
console.log('Model Initialized:', { apiKey: '***', baseURL: this.baseURL, modelName: this.modelName });
}
async _generate(messages, options) {
var _a, _b, _c, _d;
console.log('Generating with messages:', messages.map(m => m.content));
let allMessages = [...messages];
const hasSystemMessage = messages.some(msg => msg._getType() === 'system');
if (!hasSystemMessage) {
const defaultSystemPrompt = new messages_1.SystemMessage({
content: "You are a friendly assistant.",
});
allMessages.unshift(defaultSystemPrompt);
}
const url = `${this.baseURL}/prompt/completion`;
const headers = {
Authorization: `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
};
const messageContent = allMessages
.map((msg) => {
if (msg._getType() === 'human')
return msg.content;
if (msg._getType() === 'ai')
return `Assistant: ${msg.content}`;
if (msg._getType() === 'system')
return `System: ${msg.content}`;
return '';
})
.filter((content) => content)
.join('\n');
let toolCalls = [];
let prompt = messageContent;
if (this.boundTools.length > 0) {
const toolsSchema = JSON.stringify(this.boundTools.map((tool) => ({
name: tool.name,
description: tool.description,
parameters: tool.schema,
})), null, 2);
prompt = `
${messageContent}
You are an AI assistant capable of calling tools. If the user request requires a tool, respond with a JSON object containing:
- tool: The name of the tool to call
- arguments: The arguments for the tool
- content: Any additional text response (optional)
Available tools:
${toolsSchema}
Return the response in JSON format.
`;
}
const smartLlmSelector = this.modelName.includes('claude') ? 'quality' : 'balance';
const body = {
smart_llm_selector: smartLlmSelector,
message: prompt,
replace_failed_models: true,
...(this.temperature && { temperature: this.temperature }),
...(this.topP && { top_p: this.topP }),
...(this.maxTokens && { max_tokens: this.maxTokens }),
...(this.presencePenalty && { presence_penalty: this.presencePenalty }),
...(this.frequencyPenalty && { frequency_penalty: this.frequencyPenalty }),
response_format: this.boundTools.length > 0 ? 'json' : 'text',
};
let attempts = 0;
while (attempts <= this.maxRetries) {
try {
const requestOptions = {
method: 'POST',
headers,
body: JSON.stringify(body),
signal: AbortSignal.timeout(this.timeout),
};
const response = await fetch(url, requestOptions);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const data = await response.json();
console.log('Straico API Response:', data);
let completion = '';
if (((_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.data) === null || _a === void 0 ? void 0 : _a.completion) === null || _b === void 0 ? void 0 : _b.choices) === null || _c === void 0 ? void 0 : _c.length) > 0) {
const choice = data.data.completion.choices[0];
completion = ((_d = choice.message) === null || _d === void 0 ? void 0 : _d.content) || choice.text || '';
}
else if ((data === null || data === void 0 ? void 0 : data.completion) || (data === null || data === void 0 ? void 0 : data.message) || (data === null || data === void 0 ? void 0 : data.text) || (data === null || data === void 0 ? void 0 : data.response) || (data === null || data === void 0 ? void 0 : data.result)) {
completion = data.completion || data.message || data.text || data.response || data.result || '';
}
else if (typeof data === 'string') {
completion = data;
}
if (this.boundTools.length > 0) {
try {
const parsed = JSON.parse(completion);
if (parsed.tool && parsed.arguments) {
toolCalls = [
{
name: parsed.tool,
args: parsed.arguments,
},
];
completion = parsed.content || '';
}
}
catch (e) {
console.log('Failed to parse tool call response as JSON:', e);
}
}
console.log('Generated Completion:', completion);
return {
generations: [
{
text: completion,
message: new messages_1.AIMessage({
content: completion,
additional_kwargs: toolCalls.length > 0 ? { tool_calls: toolCalls } : undefined,
}),
},
],
};
}
catch (error) {
console.log('Error in _generate:', error.message);
if (this.onFailedAttempt)
this.onFailedAttempt(error);
attempts++;
if (attempts > this.maxRetries) {
throw new Error(`Failed after ${this.maxRetries} retries: ${error.message}`);
}
await new Promise((resolve) => setTimeout(resolve, 1000 * attempts));
}
}
throw new Error('Unexpected error in request handling');
}
bindTools(tools) {
this.boundTools = tools;
return this;
}
_llmType() {
return 'straico';
}
}
exports.StraicoChatModel = StraicoChatModel;
//# sourceMappingURL=StraicoChatModel.js.map