@alpic80/rivet-core 1.24.0-aidon.5 → 1.24.2-aidon.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/dist/cjs/bundle.cjs +1534 -278
- package/dist/cjs/bundle.cjs.map +4 -4
- package/dist/esm/api/createProcessor.js +2 -0
- package/dist/esm/api/streaming.js +48 -2
- package/dist/esm/exports.js +1 -0
- package/dist/esm/integrations/CodeRunner.js +10 -2
- package/dist/esm/integrations/mcp/MCPBase.js +100 -0
- package/dist/esm/integrations/mcp/MCPProvider.js +23 -0
- package/dist/esm/integrations/mcp/MCPUtils.js +33 -0
- package/dist/esm/model/GraphProcessor.js +7 -1
- package/dist/esm/model/NodeRegistration.js +0 -1
- package/dist/esm/model/Nodes.js +9 -0
- package/dist/esm/model/nodes/ChatNodeBase.js +1 -1
- package/dist/esm/model/nodes/CodeNode.js +1 -1
- package/dist/esm/model/nodes/GetAllDatasetsNode.js +1 -1
- package/dist/esm/model/nodes/GraphInputNode.js +2 -0
- package/dist/esm/model/nodes/HttpCallNode.js +2 -2
- package/dist/esm/model/nodes/MCPDiscoveryNode.js +239 -0
- package/dist/esm/model/nodes/MCPGetPromptNode.js +262 -0
- package/dist/esm/model/nodes/MCPToolCallNode.js +290 -0
- package/dist/esm/model/nodes/ObjectNode.js +42 -21
- package/dist/esm/model/nodes/PromptNode.js +1 -1
- package/dist/esm/model/nodes/SubGraphNode.js +1 -0
- package/dist/esm/model/nodes/TextNode.js +13 -2
- package/dist/esm/plugins/aidon/nodes/ChatAidonNode.js +7 -5
- package/dist/esm/plugins/aidon/plugin.js +15 -0
- package/dist/esm/plugins/anthropic/anthropic.js +22 -3
- package/dist/esm/plugins/anthropic/nodes/ChatAnthropicNode.js +33 -3
- package/dist/esm/plugins/google/google.js +29 -14
- package/dist/esm/plugins/google/nodes/ChatGoogleNode.js +70 -5
- package/dist/esm/plugins/huggingface/nodes/ChatHuggingFace.js +4 -2
- package/dist/esm/plugins/huggingface/nodes/TextToImageHuggingFace.js +5 -3
- package/dist/esm/utils/interpolation.js +155 -17
- package/dist/esm/utils/openai.js +24 -0
- package/dist/types/api/createProcessor.d.ts +3 -2
- package/dist/types/api/streaming.d.ts +7 -1
- package/dist/types/exports.d.ts +1 -0
- package/dist/types/integrations/CodeRunner.d.ts +4 -3
- package/dist/types/integrations/mcp/MCPBase.d.ts +20 -0
- package/dist/types/integrations/mcp/MCPProvider.d.ts +153 -0
- package/dist/types/integrations/mcp/MCPUtils.d.ts +9 -0
- package/dist/types/model/GraphProcessor.d.ts +5 -1
- package/dist/types/model/Nodes.d.ts +13 -2
- package/dist/types/model/ProcessContext.d.ts +5 -1
- package/dist/types/model/Project.d.ts +2 -0
- package/dist/types/model/nodes/GetAllDatasetsNode.d.ts +2 -2
- package/dist/types/model/nodes/MCPDiscoveryNode.d.ts +9 -0
- package/dist/types/model/nodes/MCPGetPromptNode.d.ts +23 -0
- package/dist/types/model/nodes/MCPToolCallNode.d.ts +26 -0
- package/dist/types/model/nodes/ObjectNode.d.ts +3 -2
- package/dist/types/model/nodes/TextNode.d.ts +2 -1
- package/dist/types/plugins/anthropic/anthropic.d.ts +21 -3
- package/dist/types/plugins/anthropic/nodes/ChatAnthropicNode.d.ts +5 -0
- package/dist/types/plugins/google/google.d.ts +12 -2
- package/dist/types/plugins/google/nodes/ChatGoogleNode.d.ts +7 -0
- package/dist/types/utils/interpolation.d.ts +6 -1
- package/dist/types/utils/openai.d.ts +24 -0
- package/package.json +7 -7
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {} from '../NodeBase.js';
|
|
2
|
+
import { nanoid } from 'nanoid/non-secure';
|
|
3
|
+
import { NodeImpl } from '../NodeImpl.js';
|
|
4
|
+
import { nodeDefinition } from '../NodeDefinition.js';
|
|
5
|
+
import {} from '../GraphProcessor.js';
|
|
6
|
+
import { coerceType } from '../../index.js';
|
|
7
|
+
import { MCPError, MCPErrorType } from '../../integrations/mcp/MCPProvider.js';
|
|
8
|
+
import { coerceTypeOptional } from '../../utils/coerceType.js';
|
|
9
|
+
import { getInputOrData } from '../../utils/index.js';
|
|
10
|
+
import { getError } from '../../utils/errors.js';
|
|
11
|
+
import { getMCPBaseInputs } from '../../integrations/mcp/MCPBase.js';
|
|
12
|
+
import { getServerHelperMessage, getServerOptions, loadMCPConfiguration } from '../../integrations/mcp/MCPUtils.js';
|
|
13
|
+
import { dedent } from 'ts-dedent';
|
|
14
|
+
import {} from '../EditorDefinition.js';
|
|
15
|
+
import { interpolate } from '../../utils/interpolation.js';
|
|
16
|
+
import { keys } from '../../utils/typeSafety.js';
|
|
17
|
+
export class MCPToolCallNodeImpl extends NodeImpl {
|
|
18
|
+
static create() {
|
|
19
|
+
const chartNode = {
|
|
20
|
+
type: 'mcpToolCall',
|
|
21
|
+
title: 'MCP Tool Call',
|
|
22
|
+
id: nanoid(),
|
|
23
|
+
visualData: {
|
|
24
|
+
x: 0,
|
|
25
|
+
y: 0,
|
|
26
|
+
width: 250,
|
|
27
|
+
},
|
|
28
|
+
data: {
|
|
29
|
+
name: 'mcp-tool-call-client',
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
transportType: 'stdio',
|
|
32
|
+
serverUrl: 'http://localhost:8080/mcp',
|
|
33
|
+
headers: '',
|
|
34
|
+
serverId: '',
|
|
35
|
+
toolName: '',
|
|
36
|
+
toolArguments: dedent `
|
|
37
|
+
{
|
|
38
|
+
"key": "value"
|
|
39
|
+
}`,
|
|
40
|
+
toolCallId: '',
|
|
41
|
+
useNameInput: false,
|
|
42
|
+
useVersionInput: false,
|
|
43
|
+
useToolNameInput: true,
|
|
44
|
+
useToolArgumentsInput: true,
|
|
45
|
+
useToolCallIdInput: true,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
return chartNode;
|
|
49
|
+
}
|
|
50
|
+
getInputDefinitions() {
|
|
51
|
+
const inputs = getMCPBaseInputs(this.data);
|
|
52
|
+
if (this.data.useToolNameInput) {
|
|
53
|
+
inputs.push({
|
|
54
|
+
dataType: 'string',
|
|
55
|
+
id: 'toolName',
|
|
56
|
+
title: 'Tool Name',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (this.data.useToolArgumentsInput) {
|
|
60
|
+
inputs.push({
|
|
61
|
+
dataType: 'object',
|
|
62
|
+
id: 'toolArguments',
|
|
63
|
+
title: 'Tool Arguments',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (this.data.useToolCallIdInput) {
|
|
67
|
+
inputs.push({
|
|
68
|
+
dataType: 'object',
|
|
69
|
+
id: 'toolCallId',
|
|
70
|
+
title: 'Tool ID',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return inputs;
|
|
74
|
+
}
|
|
75
|
+
getOutputDefinitions() {
|
|
76
|
+
const outputDefinitions = [];
|
|
77
|
+
outputDefinitions.push({
|
|
78
|
+
id: 'response',
|
|
79
|
+
title: 'Response',
|
|
80
|
+
dataType: 'object',
|
|
81
|
+
description: 'Response from the Tool Call',
|
|
82
|
+
});
|
|
83
|
+
outputDefinitions.push({
|
|
84
|
+
id: 'toolCallId',
|
|
85
|
+
title: 'Tool ID',
|
|
86
|
+
dataType: 'string',
|
|
87
|
+
description: 'ID associated with the Tool Call',
|
|
88
|
+
});
|
|
89
|
+
return outputDefinitions;
|
|
90
|
+
}
|
|
91
|
+
async getEditors(context) {
|
|
92
|
+
const editors = [
|
|
93
|
+
{
|
|
94
|
+
type: 'string',
|
|
95
|
+
label: 'Name',
|
|
96
|
+
dataKey: 'name',
|
|
97
|
+
useInputToggleDataKey: 'useNameInput',
|
|
98
|
+
helperMessage: 'The name for the MCP Client',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
type: 'string',
|
|
102
|
+
label: 'Version',
|
|
103
|
+
dataKey: 'version',
|
|
104
|
+
useInputToggleDataKey: 'useVersionInput',
|
|
105
|
+
helperMessage: 'A version for the MCP Client',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
type: 'dropdown',
|
|
109
|
+
label: 'Transport Type',
|
|
110
|
+
dataKey: 'transportType',
|
|
111
|
+
options: [
|
|
112
|
+
{ label: 'HTTP', value: 'http' },
|
|
113
|
+
{ label: 'STDIO', value: 'stdio' },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'string',
|
|
118
|
+
label: 'Tool Name',
|
|
119
|
+
dataKey: 'toolName',
|
|
120
|
+
useInputToggleDataKey: 'useToolNameInput',
|
|
121
|
+
helperMessage: 'The name for the MCP Tool Call',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
type: 'code',
|
|
125
|
+
label: 'Tool Arguments',
|
|
126
|
+
dataKey: 'toolArguments',
|
|
127
|
+
language: 'json',
|
|
128
|
+
useInputToggleDataKey: 'useToolArgumentsInput',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
type: 'string',
|
|
132
|
+
label: 'Tool ID',
|
|
133
|
+
dataKey: 'toolCallId',
|
|
134
|
+
useInputToggleDataKey: 'useToolCallIdInput',
|
|
135
|
+
helperMessage: 'The ID associated with the tool call',
|
|
136
|
+
},
|
|
137
|
+
];
|
|
138
|
+
if (this.data.transportType === 'http') {
|
|
139
|
+
editors.push({
|
|
140
|
+
type: 'string',
|
|
141
|
+
label: 'Server URL',
|
|
142
|
+
dataKey: 'serverUrl',
|
|
143
|
+
useInputToggleDataKey: 'useServerUrlInput',
|
|
144
|
+
helperMessage: 'The base URL endpoint for the MCP server with `/mcp`',
|
|
145
|
+
}, {
|
|
146
|
+
type: 'code',
|
|
147
|
+
label: 'Headers',
|
|
148
|
+
dataKey: 'headers',
|
|
149
|
+
useInputToggleDataKey: 'useHeadersInput',
|
|
150
|
+
language: 'json',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else if (this.data.transportType === 'stdio') {
|
|
154
|
+
const serverOptions = await getServerOptions(context);
|
|
155
|
+
editors.push({
|
|
156
|
+
type: 'dropdown',
|
|
157
|
+
label: 'Server ID',
|
|
158
|
+
dataKey: 'serverId',
|
|
159
|
+
helperMessage: getServerHelperMessage(context, serverOptions.length),
|
|
160
|
+
options: serverOptions,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return editors;
|
|
164
|
+
}
|
|
165
|
+
getBody(context) {
|
|
166
|
+
let base;
|
|
167
|
+
let headers = '';
|
|
168
|
+
if (this.data.transportType === 'http') {
|
|
169
|
+
base = this.data.useServerUrlInput ? '(Using Server URL Input)' : this.data.serverUrl;
|
|
170
|
+
headers = this.data.useHeadersInput
|
|
171
|
+
? '\nHeaders: (Using Input)'
|
|
172
|
+
: this.data.headers?.trim()
|
|
173
|
+
? `\nHeaders: ${this.data.headers}`
|
|
174
|
+
: '';
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
base = `Server ID: ${this.data.serverId || '(None)'}`;
|
|
178
|
+
}
|
|
179
|
+
const namePart = `Name: ${this.data.name}`;
|
|
180
|
+
const versionPart = `Version: ${this.data.version}`;
|
|
181
|
+
const parts = [namePart, versionPart, base, headers];
|
|
182
|
+
if (context.executor !== 'nodejs') {
|
|
183
|
+
parts.push('(Requires Node Executor)');
|
|
184
|
+
}
|
|
185
|
+
return parts.join('\n');
|
|
186
|
+
}
|
|
187
|
+
static getUIData() {
|
|
188
|
+
return {
|
|
189
|
+
infoBoxBody: dedent `
|
|
190
|
+
Connects to an MCP (Model Context Protocol) server and gets a tool call response.
|
|
191
|
+
`,
|
|
192
|
+
infoBoxTitle: 'MCP Tool Call Node',
|
|
193
|
+
contextMenuTitle: 'MCP Tool Call',
|
|
194
|
+
group: ['MCP'],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async process(inputs, context) {
|
|
198
|
+
const name = getInputOrData(this.data, inputs, 'name', 'string');
|
|
199
|
+
const version = getInputOrData(this.data, inputs, 'version', 'string');
|
|
200
|
+
const toolName = getInputOrData(this.data, inputs, 'toolName', 'string');
|
|
201
|
+
const toolCallId = getInputOrData(this.data, inputs, 'toolCallId', 'string');
|
|
202
|
+
let toolArguments;
|
|
203
|
+
if (this.data.useToolArgumentsInput) {
|
|
204
|
+
toolArguments = getInputOrData(this.data, inputs, 'toolArguments', 'object');
|
|
205
|
+
if (toolArguments == null) {
|
|
206
|
+
throw new MCPError(MCPErrorType.INVALID_SCHEMA, 'Cannot parse tool argument with input toggle on');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const inputMap = keys(inputs)
|
|
211
|
+
.filter((key) => key.startsWith('input'))
|
|
212
|
+
.reduce((acc, key) => {
|
|
213
|
+
const stringValue = coerceTypeOptional(inputs[key], 'string') ?? '';
|
|
214
|
+
const interpolationKey = key.slice('input-'.length);
|
|
215
|
+
acc[interpolationKey] = stringValue;
|
|
216
|
+
return acc;
|
|
217
|
+
}, {});
|
|
218
|
+
const interpolated = interpolate(this.data.toolArguments ?? '', inputMap);
|
|
219
|
+
toolArguments = JSON.parse(interpolated);
|
|
220
|
+
}
|
|
221
|
+
const toolCall = {
|
|
222
|
+
name: toolName,
|
|
223
|
+
arguments: toolArguments,
|
|
224
|
+
};
|
|
225
|
+
const transportType = getInputOrData(this.data, inputs, 'transportType', 'string');
|
|
226
|
+
let toolResponse = undefined;
|
|
227
|
+
try {
|
|
228
|
+
if (!context.mcpProvider) {
|
|
229
|
+
throw new Error('MCP Provider not found');
|
|
230
|
+
}
|
|
231
|
+
if (transportType === 'http') {
|
|
232
|
+
const serverUrl = getInputOrData(this.data, inputs, 'serverUrl', 'string');
|
|
233
|
+
if (!serverUrl || serverUrl === '') {
|
|
234
|
+
throw new MCPError(MCPErrorType.SERVER_NOT_FOUND, 'No server URL was provided');
|
|
235
|
+
}
|
|
236
|
+
if (!serverUrl.includes('/mcp')) {
|
|
237
|
+
throw new MCPError(MCPErrorType.SERVER_COMMUNICATION_FAILED, 'Include /mcp in your server URL. For example: http://localhost:8080/mcp');
|
|
238
|
+
}
|
|
239
|
+
let headers;
|
|
240
|
+
if (this.data.useHeadersInput) {
|
|
241
|
+
const headersInput = inputs['headers'];
|
|
242
|
+
if (headersInput?.type === 'string') {
|
|
243
|
+
headers = JSON.parse(headersInput.value);
|
|
244
|
+
}
|
|
245
|
+
else if (headersInput?.type === 'object') {
|
|
246
|
+
headers = headersInput.value;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
headers = coerceType(headersInput, 'object');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else if (this.data.headers?.trim()) {
|
|
253
|
+
headers = JSON.parse(this.data.headers);
|
|
254
|
+
}
|
|
255
|
+
toolResponse = await context.mcpProvider.httpToolCall({ name, version }, serverUrl, headers, toolCall);
|
|
256
|
+
}
|
|
257
|
+
else if (transportType === 'stdio') {
|
|
258
|
+
const serverId = this.data.serverId ?? '';
|
|
259
|
+
const mcpConfig = await loadMCPConfiguration(context);
|
|
260
|
+
if (!mcpConfig.mcpServers[serverId]) {
|
|
261
|
+
throw new MCPError(MCPErrorType.SERVER_NOT_FOUND, `Server ${serverId} not found in MCP config`);
|
|
262
|
+
}
|
|
263
|
+
const serverConfig = {
|
|
264
|
+
config: mcpConfig.mcpServers[serverId],
|
|
265
|
+
serverId,
|
|
266
|
+
};
|
|
267
|
+
toolResponse = await context.mcpProvider.stdioToolCall({ name, version }, serverConfig, toolCall);
|
|
268
|
+
}
|
|
269
|
+
const output = {};
|
|
270
|
+
output['response'] = {
|
|
271
|
+
type: 'object[]',
|
|
272
|
+
value: toolResponse?.content,
|
|
273
|
+
};
|
|
274
|
+
output['toolCallId'] = {
|
|
275
|
+
type: 'string',
|
|
276
|
+
value: toolCallId,
|
|
277
|
+
};
|
|
278
|
+
return output;
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
const { message } = getError(err);
|
|
282
|
+
if (context.executor === 'browser') {
|
|
283
|
+
throw new Error('Failed to create Client without a node executor');
|
|
284
|
+
}
|
|
285
|
+
console.log(message);
|
|
286
|
+
throw err;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
export const mcpToolCallNode = nodeDefinition(MCPToolCallNodeImpl, 'MCP Tool Call');
|
|
@@ -5,6 +5,7 @@ import { nodeDefinition } from '../NodeDefinition.js';
|
|
|
5
5
|
import {} from '../DataValue.js';
|
|
6
6
|
import { dedent } from 'ts-dedent';
|
|
7
7
|
import {} from '../EditorDefinition.js';
|
|
8
|
+
import { resolveExpressionRawValue, unwrapPotentialDataValue } from '../../utils/interpolation.js';
|
|
8
9
|
const DEFAULT_JSON_TEMPLATE = `{
|
|
9
10
|
"key": "{{input}}"
|
|
10
11
|
}`;
|
|
@@ -26,17 +27,23 @@ export class ObjectNodeImpl extends NodeImpl {
|
|
|
26
27
|
return chartNode;
|
|
27
28
|
}
|
|
28
29
|
getInputDefinitions() {
|
|
29
|
-
//
|
|
30
|
-
const
|
|
31
|
-
|
|
30
|
+
// Provide default empty string for jsonTemplate if undefined
|
|
31
|
+
const jsonTemplate = this.chartNode.data.jsonTemplate ?? '';
|
|
32
|
+
const matches = jsonTemplate.match(/\{\{([^}]+?)\}\}/g); // matches is string[] | null
|
|
33
|
+
const allTokens = matches ?? []; // allTokens is now explicitly string[]
|
|
34
|
+
const inputTokens = allTokens
|
|
35
|
+
// id and title should not have the {{ and }}
|
|
36
|
+
.map((token) => token.slice(2, -2).trim())
|
|
37
|
+
.filter((tokenContent) => !tokenContent.startsWith('@graphInputs.') && !tokenContent.startsWith('@context.'))
|
|
38
|
+
.filter((token) => token !== '');
|
|
39
|
+
return [...new Set(inputTokens)].map((inputName) => {
|
|
32
40
|
return {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
title: inputName.slice(2, -2),
|
|
41
|
+
id: inputName,
|
|
42
|
+
title: inputName,
|
|
36
43
|
dataType: 'any',
|
|
37
44
|
required: false,
|
|
38
45
|
};
|
|
39
|
-
})
|
|
46
|
+
});
|
|
40
47
|
}
|
|
41
48
|
getOutputDefinitions() {
|
|
42
49
|
return [
|
|
@@ -77,10 +84,22 @@ export class ObjectNodeImpl extends NodeImpl {
|
|
|
77
84
|
group: ['Objects'],
|
|
78
85
|
};
|
|
79
86
|
}
|
|
80
|
-
interpolate(baseString, values) {
|
|
81
|
-
return baseString.replace(/("?)\{\{([^}]
|
|
87
|
+
interpolate(baseString, values, graphInputNodeValues, contextValues) {
|
|
88
|
+
return baseString.replace(/("?)\{\{([^}]+?)\}\}("?)/g, (_m, openQuote, key, _closeQuote) => {
|
|
82
89
|
const isQuoted = Boolean(openQuote);
|
|
83
|
-
const
|
|
90
|
+
const trimmedKey = key.trim(); // Use trimmedKey for lookups
|
|
91
|
+
let value;
|
|
92
|
+
const graphInputPrefix = '@graphInputs.';
|
|
93
|
+
const contextPrefix = '@context.';
|
|
94
|
+
if (trimmedKey.startsWith(graphInputPrefix) && graphInputNodeValues) {
|
|
95
|
+
value = resolveExpressionRawValue(graphInputNodeValues, trimmedKey.substring(graphInputPrefix.length), 'graphInputs');
|
|
96
|
+
}
|
|
97
|
+
else if (trimmedKey.startsWith(contextPrefix) && contextValues) {
|
|
98
|
+
value = resolveExpressionRawValue(contextValues, trimmedKey.substring(contextPrefix.length), 'context');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
value = values[trimmedKey]; // Original logic for non-@ variables
|
|
102
|
+
}
|
|
84
103
|
if (value == null) {
|
|
85
104
|
return 'null';
|
|
86
105
|
}
|
|
@@ -96,23 +115,25 @@ export class ObjectNodeImpl extends NodeImpl {
|
|
|
96
115
|
return JSON.stringify(value);
|
|
97
116
|
});
|
|
98
117
|
}
|
|
99
|
-
async process(inputs) {
|
|
118
|
+
async process(inputs, context) {
|
|
100
119
|
const inputMap = Object.keys(inputs).reduce((acc, key) => {
|
|
101
|
-
acc[key] = inputs[key]
|
|
120
|
+
acc[key] = unwrapPotentialDataValue(inputs[key]);
|
|
102
121
|
return acc;
|
|
103
122
|
}, {});
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
123
|
+
const interpolatedString = this.interpolate(this.chartNode.data.jsonTemplate, inputMap, context.graphInputNodeValues, // Pass graph inputs
|
|
124
|
+
context.contextValues // Pass context values
|
|
125
|
+
);
|
|
126
|
+
let outputValue;
|
|
127
|
+
try {
|
|
128
|
+
outputValue = JSON.parse(interpolatedString);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
throw new Error(`Failed to parse JSON template: ${err.message}`);
|
|
112
132
|
}
|
|
133
|
+
const outputType = Array.isArray(outputValue) ? 'object[]' : 'object';
|
|
113
134
|
return {
|
|
114
135
|
output: {
|
|
115
|
-
type:
|
|
136
|
+
type: outputType,
|
|
116
137
|
value: outputValue,
|
|
117
138
|
},
|
|
118
139
|
};
|
|
@@ -177,7 +177,7 @@ export class PromptNodeImpl extends NodeImpl {
|
|
|
177
177
|
}
|
|
178
178
|
async process(inputs, context) {
|
|
179
179
|
const inputMap = mapValues(inputs, (input) => coerceType(input, 'string'));
|
|
180
|
-
const outputValue = interpolate(this.chartNode.data.promptText, inputMap);
|
|
180
|
+
const outputValue = interpolate(this.chartNode.data.promptText, inputMap, context.graphInputNodeValues, context.contextValues);
|
|
181
181
|
const type = getInputOrData(this.data, inputs, 'type', 'string');
|
|
182
182
|
const isCacheBreakpoint = getInputOrData(this.data, inputs, 'isCacheBreakpoint', 'boolean');
|
|
183
183
|
if (['assistant', 'system', 'user', 'function'].includes(type) === false) {
|
|
@@ -20,6 +20,7 @@ export class TextNodeImpl extends NodeImpl {
|
|
|
20
20
|
},
|
|
21
21
|
data: {
|
|
22
22
|
text: '{{input}}',
|
|
23
|
+
normalizeLineEndings: true, // Default to true for better compatibility
|
|
23
24
|
},
|
|
24
25
|
};
|
|
25
26
|
return chartNode;
|
|
@@ -61,6 +62,12 @@ export class TextNodeImpl extends NodeImpl {
|
|
|
61
62
|
language: 'prompt-interpolation-markdown',
|
|
62
63
|
theme: 'prompt-interpolation',
|
|
63
64
|
},
|
|
65
|
+
{
|
|
66
|
+
type: 'toggle',
|
|
67
|
+
label: 'Normalize Line Endings',
|
|
68
|
+
dataKey: 'normalizeLineEndings',
|
|
69
|
+
helperMessage: 'Normalize line endings to use only LF (\\n) instead of CRLF (\\r\\n).',
|
|
70
|
+
},
|
|
64
71
|
];
|
|
65
72
|
}
|
|
66
73
|
getBody() {
|
|
@@ -72,13 +79,17 @@ export class TextNodeImpl extends NodeImpl {
|
|
|
72
79
|
text: truncated,
|
|
73
80
|
};
|
|
74
81
|
}
|
|
75
|
-
async process(inputs) {
|
|
82
|
+
async process(inputs, context) {
|
|
76
83
|
const inputMap = Object.keys(inputs).reduce((acc, key) => {
|
|
77
84
|
const stringValue = coerceTypeOptional(inputs[key], 'string') ?? '';
|
|
78
85
|
acc[key] = stringValue;
|
|
79
86
|
return acc;
|
|
80
87
|
}, {});
|
|
81
|
-
|
|
88
|
+
let outputValue = interpolate(this.chartNode.data.text, inputMap, context.graphInputNodeValues, // Pass graph inputs
|
|
89
|
+
context.contextValues);
|
|
90
|
+
if (this.chartNode.data.normalizeLineEndings) {
|
|
91
|
+
outputValue = outputValue.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
92
|
+
}
|
|
82
93
|
return {
|
|
83
94
|
output: {
|
|
84
95
|
type: 'string',
|
|
@@ -53,7 +53,7 @@ class ChatAidonNodeImpl extends ChatNodeImpl {
|
|
|
53
53
|
}
|
|
54
54
|
return path;
|
|
55
55
|
}
|
|
56
|
-
async callToolGet(
|
|
56
|
+
async callToolGet(schemaDetail, path, parsedArgs, data) {
|
|
57
57
|
const queryParams = new URLSearchParams(parsedArgs.parameters).toString();
|
|
58
58
|
const fullUrl = schemaDetail.url + path + (queryParams ? "?" + queryParams : "");
|
|
59
59
|
let headers = {};
|
|
@@ -112,8 +112,11 @@ class ChatAidonNodeImpl extends ChatNodeImpl {
|
|
|
112
112
|
async process(inputs, context) {
|
|
113
113
|
//make sure not to include functions if we have no way to run them after.
|
|
114
114
|
inputs = this.removeInvalidInputs(inputs);
|
|
115
|
+
// const configData = this.data
|
|
116
|
+
// configData.frequencyPenalty = 2;
|
|
115
117
|
// Call the parent class's process method to do its job
|
|
116
118
|
let outputs = await super.process(inputs, context);
|
|
119
|
+
//Now check if the LLM wants us to do some tool calling
|
|
117
120
|
const funcCallOutput = outputs['function-call'] ?? outputs['function-calls'];
|
|
118
121
|
const funcCalls = funcCallOutput?.type === 'object[]'
|
|
119
122
|
? funcCallOutput.value
|
|
@@ -135,14 +138,13 @@ class ChatAidonNodeImpl extends ChatNodeImpl {
|
|
|
135
138
|
}
|
|
136
139
|
const schemaDetail = this.convertToolSchemaToSchemaDetail(toolSchema);
|
|
137
140
|
const path = this.extractPath(schemaDetail, functionCall.name, functionCall.arguments);
|
|
138
|
-
// Determine if the request should be in the body or as a query
|
|
139
141
|
let data = {};
|
|
140
|
-
if
|
|
141
|
-
|
|
142
|
+
// Determine if the request should be in the body or as a query
|
|
143
|
+
if (schemaDetail.requestInBody) { // If the type is set to body
|
|
142
144
|
data = await this.callToolPost(schemaDetail, path, functionCall.arguments, data);
|
|
143
145
|
}
|
|
144
146
|
else { // If the type is set to query
|
|
145
|
-
data = await this.callToolGet(
|
|
147
|
+
data = await this.callToolGet(schemaDetail, path, functionCall.arguments, data);
|
|
146
148
|
}
|
|
147
149
|
messages['value'].push({
|
|
148
150
|
type: "function",
|
|
@@ -3,6 +3,21 @@ import { chatAidonNode } from './nodes/ChatAidonNode.js';
|
|
|
3
3
|
export const aidonPlugin = {
|
|
4
4
|
id: 'aidon',
|
|
5
5
|
name: 'Aidon',
|
|
6
|
+
configSpec: {
|
|
7
|
+
aidonURL: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
label: 'Aidon URL',
|
|
10
|
+
description: 'The URL for the Aidon application.',
|
|
11
|
+
helperText: 'Defaults to https://app.aidon.ai. URL for the Aidon application.',
|
|
12
|
+
default: 'https://app.aidon.ai',
|
|
13
|
+
},
|
|
14
|
+
aidonKey: {
|
|
15
|
+
type: 'secret',
|
|
16
|
+
label: 'Aidon API Key',
|
|
17
|
+
description: 'The API Key for the Aidon application.',
|
|
18
|
+
helperText: 'API Key for the Aidon application.',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
6
21
|
register: (register) => {
|
|
7
22
|
register(chatAidonNode());
|
|
8
23
|
},
|
|
@@ -80,12 +80,28 @@ export const anthropicModels = {
|
|
|
80
80
|
},
|
|
81
81
|
displayName: 'Claude 3.7 Sonnet',
|
|
82
82
|
},
|
|
83
|
+
'claude-sonnet-4-20250514': {
|
|
84
|
+
maxTokens: 200_000,
|
|
85
|
+
cost: {
|
|
86
|
+
prompt: 3e-6,
|
|
87
|
+
completion: 3.75e-6,
|
|
88
|
+
},
|
|
89
|
+
displayName: 'Claude Sonnet 4',
|
|
90
|
+
},
|
|
91
|
+
'claude-opus-4-20250514': {
|
|
92
|
+
maxTokens: 200_000,
|
|
93
|
+
cost: {
|
|
94
|
+
prompt: 15e-6,
|
|
95
|
+
completion: 18.75e-6,
|
|
96
|
+
},
|
|
97
|
+
displayName: 'Claude Opus 4',
|
|
98
|
+
},
|
|
83
99
|
};
|
|
84
100
|
export const anthropicModelOptions = Object.entries(anthropicModels).map(([id, { displayName }]) => ({
|
|
85
101
|
value: id,
|
|
86
102
|
label: displayName,
|
|
87
103
|
}));
|
|
88
|
-
export async function* streamChatCompletions({ apiEndpoint, apiKey, signal, ...rest }) {
|
|
104
|
+
export async function* streamChatCompletions({ apiEndpoint, apiKey, signal, additionalHeaders, ...rest }) {
|
|
89
105
|
const defaultSignal = new AbortController().signal;
|
|
90
106
|
const response = await fetchEventSource(`${apiEndpoint}/completions`, {
|
|
91
107
|
method: 'POST',
|
|
@@ -94,6 +110,7 @@ export async function* streamChatCompletions({ apiEndpoint, apiKey, signal, ...r
|
|
|
94
110
|
'x-api-key': apiKey,
|
|
95
111
|
'anthropic-version': '2023-06-01',
|
|
96
112
|
'anthropic-dangerous-direct-browser-access': 'true',
|
|
113
|
+
...additionalHeaders,
|
|
97
114
|
},
|
|
98
115
|
body: JSON.stringify({
|
|
99
116
|
...rest,
|
|
@@ -125,7 +142,7 @@ export async function* streamChatCompletions({ apiEndpoint, apiKey, signal, ...r
|
|
|
125
142
|
throw new AnthropicError(`No chunks received. Response: ${JSON.stringify(responseJson)}`, response, responseJson);
|
|
126
143
|
}
|
|
127
144
|
}
|
|
128
|
-
export async function callMessageApi({ apiEndpoint, apiKey, signal, tools, beta, ...rest }) {
|
|
145
|
+
export async function callMessageApi({ apiEndpoint, apiKey, signal, tools, beta, additionalHeaders, ...rest }) {
|
|
129
146
|
const defaultSignal = new AbortController().signal;
|
|
130
147
|
const response = await fetch(`${apiEndpoint}/messages`, {
|
|
131
148
|
method: 'POST',
|
|
@@ -135,6 +152,7 @@ export async function callMessageApi({ apiEndpoint, apiKey, signal, tools, beta,
|
|
|
135
152
|
'anthropic-version': '2023-06-01',
|
|
136
153
|
'anthropic-dangerous-direct-browser-access': 'true',
|
|
137
154
|
...(beta ? { 'anthropic-beta': beta } : {}),
|
|
155
|
+
...additionalHeaders,
|
|
138
156
|
},
|
|
139
157
|
body: JSON.stringify({
|
|
140
158
|
...rest,
|
|
@@ -149,7 +167,7 @@ export async function callMessageApi({ apiEndpoint, apiKey, signal, tools, beta,
|
|
|
149
167
|
}
|
|
150
168
|
return responseJson;
|
|
151
169
|
}
|
|
152
|
-
export async function* streamMessageApi({ apiEndpoint, apiKey, signal, beta, ...rest }) {
|
|
170
|
+
export async function* streamMessageApi({ apiEndpoint, apiKey, signal, beta, additionalHeaders, ...rest }) {
|
|
153
171
|
// Use the Messages API for Claude 3 models
|
|
154
172
|
const defaultSignal = new AbortController().signal;
|
|
155
173
|
const response = await fetchEventSource(`${apiEndpoint}/messages`, {
|
|
@@ -160,6 +178,7 @@ export async function* streamMessageApi({ apiEndpoint, apiKey, signal, beta, ...
|
|
|
160
178
|
'anthropic-version': '2023-06-01',
|
|
161
179
|
'anthropic-dangerous-direct-browser-access': 'true',
|
|
162
180
|
...(beta ? { 'anthropic-beta': beta } : {}),
|
|
181
|
+
...additionalHeaders,
|
|
163
182
|
},
|
|
164
183
|
body: JSON.stringify({
|
|
165
184
|
...rest,
|
|
@@ -12,7 +12,7 @@ import { getScalarTypeOf, isArrayDataValue } from '../../../model/DataValue.js';
|
|
|
12
12
|
import { assertNever } from '../../../utils/assertNever.js';
|
|
13
13
|
import { isNotNull } from '../../../utils/genericUtilFunctions.js';
|
|
14
14
|
import { uint8ArrayToBase64 } from '../../../utils/base64.js';
|
|
15
|
-
import { getInputOrData } from '../../../utils/inputs.js';
|
|
15
|
+
import { getInputOrData, cleanHeaders } from '../../../utils/inputs.js';
|
|
16
16
|
// Temporary
|
|
17
17
|
const cache = new Map();
|
|
18
18
|
export const ChatAnthropicNodeImpl = {
|
|
@@ -27,7 +27,7 @@ export const ChatAnthropicNodeImpl = {
|
|
|
27
27
|
width: 275,
|
|
28
28
|
},
|
|
29
29
|
data: {
|
|
30
|
-
model: 'claude-
|
|
30
|
+
model: 'claude-sonnet-4-20250514',
|
|
31
31
|
useModelInput: false,
|
|
32
32
|
temperature: 0.5,
|
|
33
33
|
useTemperatureInput: false,
|
|
@@ -120,6 +120,14 @@ export const ChatAnthropicNodeImpl = {
|
|
|
120
120
|
coerced: false,
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
|
+
if (data.useHeadersInput) {
|
|
124
|
+
inputs.push({
|
|
125
|
+
dataType: 'object',
|
|
126
|
+
id: 'headers',
|
|
127
|
+
title: 'Headers',
|
|
128
|
+
description: 'Additional headers to send to the API.',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
123
131
|
return inputs;
|
|
124
132
|
},
|
|
125
133
|
getOutputDefinitions(data) {
|
|
@@ -267,6 +275,14 @@ export const ChatAnthropicNodeImpl = {
|
|
|
267
275
|
useInputToggleDataKey: 'useOverrideModelInput',
|
|
268
276
|
helperMessage: 'Overrides the AI model used for the chat node to this value.',
|
|
269
277
|
},
|
|
278
|
+
{
|
|
279
|
+
type: 'keyValuePair',
|
|
280
|
+
label: 'Headers',
|
|
281
|
+
dataKey: 'headers',
|
|
282
|
+
useInputToggleDataKey: 'useHeadersInput',
|
|
283
|
+
keyPlaceholder: 'Header',
|
|
284
|
+
helperMessage: 'Additional headers to send to the API.',
|
|
285
|
+
},
|
|
270
286
|
],
|
|
271
287
|
},
|
|
272
288
|
];
|
|
@@ -343,6 +359,18 @@ export const ChatAnthropicNodeImpl = {
|
|
|
343
359
|
addWarning(output, message);
|
|
344
360
|
maxTokens = Math.floor((modelInfo.maxTokens - tokenCountEstimate) * 0.95); // reduce max tokens by 5% to be safe, calculation is a little wrong.
|
|
345
361
|
}
|
|
362
|
+
const headersFromData = (data.headers ?? []).reduce((acc, header) => {
|
|
363
|
+
acc[header.key] = header.value;
|
|
364
|
+
return acc;
|
|
365
|
+
}, {});
|
|
366
|
+
const additionalHeaders = data.useHeadersInput
|
|
367
|
+
? coerceTypeOptional(inputs['headers'], 'object') ??
|
|
368
|
+
headersFromData
|
|
369
|
+
: headersFromData;
|
|
370
|
+
const allAdditionalHeaders = cleanHeaders({
|
|
371
|
+
...context.settings.chatNodeHeaders,
|
|
372
|
+
...additionalHeaders,
|
|
373
|
+
});
|
|
346
374
|
try {
|
|
347
375
|
return await retry(async () => {
|
|
348
376
|
const completionOptions = {
|
|
@@ -365,7 +393,7 @@ export const ChatAnthropicNodeImpl = {
|
|
|
365
393
|
? tools.map((tool) => ({ name: tool.name, description: tool.description, input_schema: tool.parameters }))
|
|
366
394
|
: undefined,
|
|
367
395
|
};
|
|
368
|
-
const useMessageApi = model.startsWith('claude-3');
|
|
396
|
+
const useMessageApi = model.startsWith('claude-3') || model.startsWith('claude-sonnet') || model.startsWith('claude-opus');
|
|
369
397
|
const cacheKey = JSON.stringify(useMessageApi ? messageOptions : completionOptions);
|
|
370
398
|
if (data.cache) {
|
|
371
399
|
const cached = cache.get(cacheKey);
|
|
@@ -385,6 +413,7 @@ export const ChatAnthropicNodeImpl = {
|
|
|
385
413
|
apiKey: apiKey ?? '',
|
|
386
414
|
signal: context.signal,
|
|
387
415
|
beta: 'prompt-caching-2024-07-31',
|
|
416
|
+
additionalHeaders: allAdditionalHeaders,
|
|
388
417
|
...messageOptions,
|
|
389
418
|
});
|
|
390
419
|
// Process the response chunks and update the output
|
|
@@ -516,6 +545,7 @@ export const ChatAnthropicNodeImpl = {
|
|
|
516
545
|
apiEndpoint,
|
|
517
546
|
apiKey: apiKey ?? '',
|
|
518
547
|
signal: context.signal,
|
|
548
|
+
additionalHeaders: allAdditionalHeaders,
|
|
519
549
|
...completionOptions,
|
|
520
550
|
});
|
|
521
551
|
// Process the response chunks and update the output
|