@alpic80/rivet-core 1.19.1-aidon.3 → 1.24.0-aidon.1
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 +4 -0
- package/dist/cjs/bundle.cjs +3993 -943
- package/dist/cjs/bundle.cjs.map +4 -4
- package/dist/esm/api/createProcessor.js +8 -17
- package/dist/esm/api/looseDataValue.js +16 -0
- package/dist/esm/exports.js +2 -0
- package/dist/esm/integrations/CodeRunner.js +36 -0
- package/dist/esm/integrations/GptTokenizerTokenizer.js +7 -4
- package/dist/esm/integrations/openai/OpenAIEmbeddingGenerator.js +1 -1
- package/dist/esm/model/DataValue.js +14 -2
- package/dist/esm/model/GraphProcessor.js +275 -104
- package/dist/esm/model/NodeBase.js +11 -1
- package/dist/esm/model/NodeImpl.js +8 -0
- package/dist/esm/model/Nodes.js +28 -4
- package/dist/esm/model/ProjectReferenceLoader.js +1 -0
- package/dist/esm/model/nodes/AssembleMessageNode.js +12 -2
- package/dist/esm/model/nodes/AssemblePromptNode.js +22 -0
- package/dist/esm/model/nodes/CallGraphNode.js +3 -4
- package/dist/esm/model/nodes/ChatLoopNode.js +150 -0
- package/dist/esm/model/nodes/ChatNode.js +7 -934
- package/dist/esm/model/nodes/ChatNodeBase.js +1275 -0
- package/dist/esm/model/nodes/ChunkNode.js +2 -2
- package/dist/esm/model/nodes/CodeNode.js +40 -4
- package/dist/esm/model/nodes/CronNode.js +248 -0
- package/dist/esm/model/nodes/DelegateFunctionCallNode.js +37 -12
- package/dist/esm/model/nodes/DestructureNode.js +1 -1
- package/dist/esm/model/nodes/DocumentNode.js +183 -0
- package/dist/esm/model/nodes/ExtractJsonNode.js +4 -4
- package/dist/esm/model/nodes/ExtractRegexNode.js +10 -11
- package/dist/esm/model/nodes/GetEmbeddingNode.js +1 -1
- package/dist/esm/model/nodes/HttpCallNode.js +3 -1
- package/dist/esm/model/nodes/IfNode.js +5 -0
- package/dist/esm/model/nodes/LoopUntilNode.js +214 -0
- package/dist/esm/model/nodes/PromptNode.js +29 -6
- package/dist/esm/model/nodes/ReadAllFilesNode.js +210 -0
- package/dist/esm/model/nodes/ReadDirectoryNode.js +31 -25
- package/dist/esm/model/nodes/ReferencedGraphAliasNode.js +199 -0
- package/dist/esm/model/nodes/TextNode.js +9 -4
- package/dist/esm/model/nodes/ToMarkdownTableNode.js +119 -0
- package/dist/esm/model/nodes/ToTreeNode.js +133 -0
- package/dist/esm/model/nodes/{GptFunctionNode.js → ToolNode.js} +10 -10
- package/dist/esm/model/nodes/UserInputNode.js +10 -12
- package/dist/esm/plugins/aidon/nodes/ChatAidonNode.js +2 -2
- package/dist/esm/plugins/anthropic/anthropic.js +29 -10
- package/dist/esm/plugins/anthropic/fetchEventSource.js +3 -2
- package/dist/esm/plugins/anthropic/nodes/ChatAnthropicNode.js +267 -147
- package/dist/esm/plugins/anthropic/plugin.js +9 -1
- package/dist/esm/plugins/gentrace/plugin.js +6 -6
- package/dist/esm/plugins/google/google.js +113 -5
- package/dist/esm/plugins/google/nodes/ChatGoogleNode.js +211 -54
- package/dist/esm/plugins/google/plugin.js +13 -6
- package/dist/esm/plugins/openai/nodes/RunThreadNode.js +2 -2
- package/dist/esm/recording/ExecutionRecorder.js +5 -1
- package/dist/esm/utils/chatMessageToOpenAIChatCompletionMessage.js +15 -2
- package/dist/esm/utils/coerceType.js +1 -1
- package/dist/esm/utils/fetchEventSource.js +1 -1
- package/dist/esm/utils/interpolation.js +108 -3
- package/dist/esm/utils/openai.js +106 -50
- package/dist/esm/utils/paths.js +80 -0
- package/dist/esm/utils/serialization/serialization_v4.js +5 -0
- package/dist/types/api/createProcessor.d.ts +11 -5
- package/dist/types/api/looseDataValue.d.ts +4 -0
- package/dist/types/api/streaming.d.ts +1 -1
- package/dist/types/exports.d.ts +2 -0
- package/dist/types/integrations/CodeRunner.d.ts +18 -0
- package/dist/types/model/DataValue.d.ts +29 -6
- package/dist/types/model/EditorDefinition.d.ts +6 -1
- package/dist/types/model/GraphProcessor.d.ts +14 -7
- package/dist/types/model/NodeBase.d.ts +4 -0
- package/dist/types/model/NodeImpl.d.ts +5 -4
- package/dist/types/model/Nodes.d.ts +12 -4
- package/dist/types/model/ProcessContext.d.ts +16 -1
- package/dist/types/model/Project.d.ts +19 -7
- package/dist/types/model/ProjectReferenceLoader.d.ts +5 -0
- package/dist/types/model/RivetPlugin.d.ts +6 -0
- package/dist/types/model/RivetUIContext.d.ts +5 -1
- package/dist/types/model/Settings.d.ts +1 -0
- package/dist/types/model/nodes/AssemblePromptNode.d.ts +4 -1
- package/dist/types/model/nodes/ChatLoopNode.d.ts +21 -0
- package/dist/types/model/nodes/ChatNode.d.ts +2 -62
- package/dist/types/model/nodes/ChatNodeBase.d.ts +85 -0
- package/dist/types/model/nodes/CodeNode.d.ts +8 -2
- package/dist/types/model/nodes/CronNode.d.ts +34 -0
- package/dist/types/model/nodes/DelegateFunctionCallNode.d.ts +1 -0
- package/dist/types/model/nodes/DocumentNode.d.ts +28 -0
- package/dist/types/model/nodes/LoopUntilNode.d.ts +32 -0
- package/dist/types/model/nodes/PromptNode.d.ts +2 -0
- package/dist/types/model/nodes/ReadAllFilesNode.d.ts +30 -0
- package/dist/types/model/nodes/ReadDirectoryNode.d.ts +1 -1
- package/dist/types/model/nodes/ReferencedGraphAliasNode.d.ts +31 -0
- package/dist/types/model/nodes/ToMarkdownTableNode.d.ts +19 -0
- package/dist/types/model/nodes/ToTreeNode.d.ts +21 -0
- package/dist/types/model/nodes/UserInputNode.d.ts +2 -3
- package/dist/types/plugins/anthropic/anthropic.d.ts +94 -13
- package/dist/types/plugins/anthropic/nodes/ChatAnthropicNode.d.ts +7 -2
- package/dist/types/plugins/google/google.d.ts +93 -18
- package/dist/types/plugins/google/nodes/ChatGoogleNode.d.ts +3 -2
- package/dist/types/recording/RecordedEvents.d.ts +2 -0
- package/dist/types/utils/base64.d.ts +1 -1
- package/dist/types/utils/chatMessageToOpenAIChatCompletionMessage.d.ts +3 -1
- package/dist/types/utils/interpolation.d.ts +3 -0
- package/dist/types/utils/openai.d.ts +127 -21
- package/dist/types/utils/paths.d.ts +8 -0
- package/package.json +15 -11
- /package/dist/types/model/nodes/{GptFunctionNode.d.ts → ToolNode.d.ts} +0 -0
|
@@ -3,7 +3,7 @@ import { NodeImpl } from '../../model/NodeImpl.js';
|
|
|
3
3
|
import { nanoid } from 'nanoid/non-secure';
|
|
4
4
|
import { coerceType } from '../../utils/coerceType.js';
|
|
5
5
|
import { dedent } from 'ts-dedent';
|
|
6
|
-
import { openAiModelOptions
|
|
6
|
+
import { openAiModelOptions } from '../../utils/openai.js';
|
|
7
7
|
import {} from '../../index.js';
|
|
8
8
|
import { nodeDefinition } from '../NodeDefinition.js';
|
|
9
9
|
export class ChunkNodeImpl extends NodeImpl {
|
|
@@ -18,7 +18,7 @@ export class ChunkNodeImpl extends NodeImpl {
|
|
|
18
18
|
width: 200,
|
|
19
19
|
},
|
|
20
20
|
data: {
|
|
21
|
-
model: 'gpt-
|
|
21
|
+
model: 'gpt-4o',
|
|
22
22
|
useModelInput: false,
|
|
23
23
|
numTokensPerChunk: 1024,
|
|
24
24
|
overlap: 0,
|
|
@@ -33,6 +33,11 @@ export class CodeNodeImpl extends NodeImpl {
|
|
|
33
33
|
`,
|
|
34
34
|
inputNames: 'input1',
|
|
35
35
|
outputNames: 'output1',
|
|
36
|
+
allowFetch: false,
|
|
37
|
+
allowRequire: false,
|
|
38
|
+
allowRivet: false,
|
|
39
|
+
allowProcess: false,
|
|
40
|
+
allowConsole: false,
|
|
36
41
|
},
|
|
37
42
|
};
|
|
38
43
|
return chartNode;
|
|
@@ -90,6 +95,33 @@ export class CodeNodeImpl extends NodeImpl {
|
|
|
90
95
|
label: 'Outputs',
|
|
91
96
|
dataKey: 'outputNames',
|
|
92
97
|
},
|
|
98
|
+
{
|
|
99
|
+
type: 'toggle',
|
|
100
|
+
label: 'Allow using `fetch`',
|
|
101
|
+
dataKey: 'allowFetch',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: 'toggle',
|
|
105
|
+
label: 'Allow using `require`',
|
|
106
|
+
dataKey: 'allowRequire',
|
|
107
|
+
helperMessage: 'This is only available when using the Node executor.',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'toggle',
|
|
111
|
+
label: 'Allow using `Rivet`',
|
|
112
|
+
dataKey: 'allowRivet',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'toggle',
|
|
116
|
+
label: 'Allow using `process`',
|
|
117
|
+
dataKey: 'allowProcess',
|
|
118
|
+
helperMessage: 'This is only available when using the Node executor.',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
type: 'toggle',
|
|
122
|
+
label: 'Allow using `console`',
|
|
123
|
+
dataKey: 'allowConsole',
|
|
124
|
+
},
|
|
93
125
|
];
|
|
94
126
|
}
|
|
95
127
|
getBody() {
|
|
@@ -117,10 +149,14 @@ export class CodeNodeImpl extends NodeImpl {
|
|
|
117
149
|
group: ['Advanced'],
|
|
118
150
|
};
|
|
119
151
|
}
|
|
120
|
-
async process(inputs) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
152
|
+
async process(inputs, context) {
|
|
153
|
+
const outputs = await context.codeRunner.runCode(this.data.code, inputs, {
|
|
154
|
+
includeFetch: this.data.allowFetch ?? false,
|
|
155
|
+
includeRequire: this.data.allowRequire ?? false,
|
|
156
|
+
includeRivet: this.data.allowRivet ?? false,
|
|
157
|
+
includeProcess: this.data.allowProcess ?? false,
|
|
158
|
+
includeConsole: this.data.allowConsole ?? false,
|
|
159
|
+
});
|
|
124
160
|
if (outputs == null || typeof outputs !== 'object' || ('then' in outputs && typeof outputs.then === 'function')) {
|
|
125
161
|
throw new Error('Code node must return an object with output values.');
|
|
126
162
|
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
2
|
+
import { NodeImpl } from '../NodeImpl.js';
|
|
3
|
+
import { dedent } from 'ts-dedent';
|
|
4
|
+
import { nodeDefinition } from '../NodeDefinition.js';
|
|
5
|
+
import { coerceType, coerceTypeOptional } from '../../utils/coerceType.js';
|
|
6
|
+
import * as cronParser from 'cron-parser';
|
|
7
|
+
export class CronNodeImpl extends NodeImpl {
|
|
8
|
+
static create() {
|
|
9
|
+
const chartNode = {
|
|
10
|
+
type: 'cron',
|
|
11
|
+
title: 'Cron',
|
|
12
|
+
id: nanoid(),
|
|
13
|
+
visualData: {
|
|
14
|
+
x: 0,
|
|
15
|
+
y: 0,
|
|
16
|
+
width: 200,
|
|
17
|
+
},
|
|
18
|
+
data: {
|
|
19
|
+
targetGraph: undefined,
|
|
20
|
+
scheduleType: 'interval',
|
|
21
|
+
schedule: '5 minutes',
|
|
22
|
+
executeImmediately: true,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
return chartNode;
|
|
26
|
+
}
|
|
27
|
+
getInputDefinitions() {
|
|
28
|
+
const inputs = [];
|
|
29
|
+
inputs.push({
|
|
30
|
+
id: 'trigger',
|
|
31
|
+
title: 'Trigger',
|
|
32
|
+
dataType: 'boolean',
|
|
33
|
+
description: 'Starts the scheduled job when true.',
|
|
34
|
+
});
|
|
35
|
+
if (this.data.useTargetGraphInput) {
|
|
36
|
+
inputs.push({
|
|
37
|
+
id: 'targetGraph',
|
|
38
|
+
title: 'Target Graph',
|
|
39
|
+
dataType: 'string',
|
|
40
|
+
description: 'The subgraph to execute on schedule',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return inputs;
|
|
44
|
+
}
|
|
45
|
+
getOutputDefinitions() {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
id: 'output',
|
|
49
|
+
title: 'Last Output',
|
|
50
|
+
dataType: 'any',
|
|
51
|
+
description: 'The last output from the subgraph execution.',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'iteration',
|
|
55
|
+
title: 'Iteration',
|
|
56
|
+
dataType: 'number',
|
|
57
|
+
description: 'The current iteration number.',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'completed',
|
|
61
|
+
title: 'Completed',
|
|
62
|
+
dataType: 'boolean',
|
|
63
|
+
description: 'True when the job has completed.',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'nextRun',
|
|
67
|
+
title: 'Next Run',
|
|
68
|
+
dataType: 'string',
|
|
69
|
+
description: 'The scheduled time for the next execution.',
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
static getUIData() {
|
|
74
|
+
return {
|
|
75
|
+
infoBoxBody: dedent `
|
|
76
|
+
Executes a subgraph on a schedule. Supports:
|
|
77
|
+
- Natural language (e.g., "every 5 minutes", "daily at 3pm")
|
|
78
|
+
- Cron expressions (e.g., "0 * * * *")
|
|
79
|
+
- Simple intervals (e.g., "5 minutes", "1 hour")
|
|
80
|
+
`,
|
|
81
|
+
infoBoxTitle: 'Cron Node',
|
|
82
|
+
contextMenuTitle: 'Cron',
|
|
83
|
+
group: ['Advanced'],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
getEditors() {
|
|
87
|
+
return [
|
|
88
|
+
{
|
|
89
|
+
type: 'toggle',
|
|
90
|
+
dataKey: 'executeImmediately',
|
|
91
|
+
label: 'Execute Immediately',
|
|
92
|
+
helperMessage: 'Starts the job immediately when the node is run, in addition to the schedule',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: 'graphSelector',
|
|
96
|
+
dataKey: 'targetGraph',
|
|
97
|
+
useInputToggleDataKey: 'useTargetGraphInput',
|
|
98
|
+
label: 'Target Graph',
|
|
99
|
+
helperMessage: 'The subgraph to execute on schedule',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
type: 'dropdown',
|
|
103
|
+
dataKey: 'scheduleType',
|
|
104
|
+
label: 'Schedule Type',
|
|
105
|
+
options: [
|
|
106
|
+
{ label: 'Cron Expression', value: 'cron' },
|
|
107
|
+
{ label: 'Simple Interval', value: 'interval' },
|
|
108
|
+
],
|
|
109
|
+
helperMessage: 'How to specify the schedule',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
type: 'string',
|
|
113
|
+
dataKey: 'schedule',
|
|
114
|
+
label: 'Schedule',
|
|
115
|
+
helperMessage: dedent `
|
|
116
|
+
Examples:
|
|
117
|
+
Cron: "*/5 * * * *", "0 15 * * *"
|
|
118
|
+
Interval: "5 minutes", "1 hour", "7 days"
|
|
119
|
+
`,
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
parseSchedule() {
|
|
124
|
+
const { scheduleType, schedule } = this.data;
|
|
125
|
+
if (scheduleType === 'cron') {
|
|
126
|
+
return { type: 'cron', expression: schedule };
|
|
127
|
+
}
|
|
128
|
+
// Parse interval
|
|
129
|
+
const match = schedule.match(/^(\d+)\s*(second|seconds|minute|minutes|hour|hours|day|days|week|weeks)$/i);
|
|
130
|
+
if (!match) {
|
|
131
|
+
throw new Error('Invalid interval format. Expected: "number unit" (e.g., "5 minutes")');
|
|
132
|
+
}
|
|
133
|
+
const value = parseInt(match[1], 10);
|
|
134
|
+
let unit = match[2].toLowerCase();
|
|
135
|
+
// Normalize unit to plural
|
|
136
|
+
if (unit.endsWith('s')) {
|
|
137
|
+
unit = unit;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
unit = `${unit}s`;
|
|
141
|
+
}
|
|
142
|
+
return { type: 'interval', value, unit };
|
|
143
|
+
}
|
|
144
|
+
getNextRunTime(schedule) {
|
|
145
|
+
const now = new Date();
|
|
146
|
+
if (schedule.type === 'interval') {
|
|
147
|
+
const { value, unit } = schedule;
|
|
148
|
+
const next = new Date(now);
|
|
149
|
+
switch (unit) {
|
|
150
|
+
case 'seconds':
|
|
151
|
+
next.setSeconds(now.getSeconds() + value);
|
|
152
|
+
break;
|
|
153
|
+
case 'minutes':
|
|
154
|
+
next.setMinutes(now.getMinutes() + value);
|
|
155
|
+
break;
|
|
156
|
+
case 'hours':
|
|
157
|
+
next.setHours(now.getHours() + value);
|
|
158
|
+
break;
|
|
159
|
+
case 'days':
|
|
160
|
+
next.setDate(now.getDate() + value);
|
|
161
|
+
break;
|
|
162
|
+
case 'weeks':
|
|
163
|
+
next.setDate(now.getDate() + value * 7);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
return next;
|
|
167
|
+
}
|
|
168
|
+
if (schedule.type === 'cron') {
|
|
169
|
+
const cron = cronParser.parseExpression(schedule.expression, { currentDate: now });
|
|
170
|
+
const next = cron.next().toDate();
|
|
171
|
+
return next;
|
|
172
|
+
}
|
|
173
|
+
throw new Error('Invalid schedule type');
|
|
174
|
+
}
|
|
175
|
+
getBody(context) {
|
|
176
|
+
if (!this.data.targetGraph && !this.data.useTargetGraphInput) {
|
|
177
|
+
return 'No target graph selected';
|
|
178
|
+
}
|
|
179
|
+
const graphName = this.data.useTargetGraphInput
|
|
180
|
+
? 'graph from input'
|
|
181
|
+
: context.project.graphs[this.data.targetGraph]?.metadata?.name ?? 'Unknown Graph';
|
|
182
|
+
return `Executes ${graphName}\n${this.data.schedule}`;
|
|
183
|
+
}
|
|
184
|
+
async process(inputs, context) {
|
|
185
|
+
if (inputs['trigger'] !== undefined) {
|
|
186
|
+
const trigger = coerceTypeOptional(inputs['trigger'], 'boolean');
|
|
187
|
+
if (!trigger) {
|
|
188
|
+
return {
|
|
189
|
+
['completed']: { type: 'boolean', value: false },
|
|
190
|
+
['iteration']: { type: 'number', value: 0 },
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!this.data.targetGraph) {
|
|
195
|
+
throw new Error('No target graph selected');
|
|
196
|
+
}
|
|
197
|
+
let iteration = 0;
|
|
198
|
+
const schedule = this.parseSchedule();
|
|
199
|
+
let lastOutputs = {};
|
|
200
|
+
let didExecuteFirstTime = !this.data.executeImmediately;
|
|
201
|
+
while (!context.signal.aborted) {
|
|
202
|
+
const nextRun = didExecuteFirstTime ? this.getNextRunTime(schedule) : new Date();
|
|
203
|
+
const delay = nextRun.getTime() - Date.now();
|
|
204
|
+
didExecuteFirstTime = true;
|
|
205
|
+
// Emit the next run time
|
|
206
|
+
const outputs = {
|
|
207
|
+
['output']: lastOutputs
|
|
208
|
+
? { type: 'object', value: lastOutputs }
|
|
209
|
+
: {
|
|
210
|
+
type: 'any',
|
|
211
|
+
value: null,
|
|
212
|
+
},
|
|
213
|
+
['iteration']: { type: 'number', value: iteration },
|
|
214
|
+
['completed']: { type: 'boolean', value: false },
|
|
215
|
+
['nextRun']: { type: 'string', value: nextRun.toISOString() },
|
|
216
|
+
};
|
|
217
|
+
if (delay > 0) {
|
|
218
|
+
await new Promise((resolve) => {
|
|
219
|
+
context.signal.addEventListener('abort', resolve, { once: true });
|
|
220
|
+
setTimeout(resolve, delay);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (context.signal.aborted) {
|
|
224
|
+
throw new Error('Aborted');
|
|
225
|
+
}
|
|
226
|
+
iteration++;
|
|
227
|
+
const subprocessor = context.createSubProcessor(this.data.targetGraph, { signal: context.signal });
|
|
228
|
+
lastOutputs = await subprocessor.processGraph(context, lastOutputs, context.contextValues);
|
|
229
|
+
// Check for break signal
|
|
230
|
+
const breakSignal = coerceTypeOptional(lastOutputs['break'], 'boolean');
|
|
231
|
+
if (breakSignal === true) {
|
|
232
|
+
return {
|
|
233
|
+
...outputs,
|
|
234
|
+
['completed']: { type: 'boolean', value: true },
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
['output']: lastOutputs
|
|
240
|
+
? { type: 'object', value: lastOutputs }
|
|
241
|
+
: { type: 'any', value: null },
|
|
242
|
+
['iteration']: { type: 'number', value: iteration },
|
|
243
|
+
['completed']: { type: 'boolean', value: true },
|
|
244
|
+
['nextRun']: { type: 'string', value: new Date().toISOString() },
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
export const cronNode = nodeDefinition(CronNodeImpl, 'Cron');
|
|
@@ -7,7 +7,7 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
7
7
|
static create() {
|
|
8
8
|
const chartNode = {
|
|
9
9
|
type: 'delegateFunctionCall',
|
|
10
|
-
title: 'Delegate
|
|
10
|
+
title: 'Delegate Tool Call',
|
|
11
11
|
id: nanoid(),
|
|
12
12
|
visualData: {
|
|
13
13
|
x: 0,
|
|
@@ -17,6 +17,7 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
17
17
|
data: {
|
|
18
18
|
handlers: [],
|
|
19
19
|
unknownHandler: undefined,
|
|
20
|
+
autoDelegate: true,
|
|
20
21
|
},
|
|
21
22
|
};
|
|
22
23
|
return chartNode;
|
|
@@ -26,10 +27,10 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
26
27
|
inputs.push({
|
|
27
28
|
id: 'function-call',
|
|
28
29
|
dataType: 'object',
|
|
29
|
-
title: '
|
|
30
|
+
title: 'Tool Call',
|
|
30
31
|
coerced: true,
|
|
31
32
|
required: true,
|
|
32
|
-
description: 'The
|
|
33
|
+
description: 'The tool call to delegate to a subgraph.',
|
|
33
34
|
});
|
|
34
35
|
return inputs;
|
|
35
36
|
}
|
|
@@ -39,7 +40,7 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
39
40
|
id: 'output',
|
|
40
41
|
dataType: 'string',
|
|
41
42
|
title: 'Output',
|
|
42
|
-
description: 'The output of the
|
|
43
|
+
description: 'The output of the tool call.',
|
|
43
44
|
});
|
|
44
45
|
outputs.push({
|
|
45
46
|
id: 'message',
|
|
@@ -52,30 +53,40 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
52
53
|
static getUIData() {
|
|
53
54
|
return {
|
|
54
55
|
infoBoxBody: dedent `
|
|
55
|
-
Handles a
|
|
56
|
+
Handles a tool call by delegating it to a different subgraph depending on the tool call.
|
|
56
57
|
`,
|
|
57
|
-
infoBoxTitle: 'Delegate
|
|
58
|
-
contextMenuTitle: 'Delegate
|
|
58
|
+
infoBoxTitle: 'Delegate Tool Call Node',
|
|
59
|
+
contextMenuTitle: 'Delegate Tool Call',
|
|
59
60
|
group: ['Advanced'],
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
getEditors() {
|
|
63
64
|
return [
|
|
65
|
+
{
|
|
66
|
+
type: 'toggle',
|
|
67
|
+
label: 'Auto Delegate',
|
|
68
|
+
dataKey: 'autoDelegate',
|
|
69
|
+
helperMessage: 'Automatically delegates tool calls to the subgraph containing the same name as the tool.',
|
|
70
|
+
},
|
|
64
71
|
{
|
|
65
72
|
type: 'custom',
|
|
66
73
|
customEditorId: 'ToolCallHandlers',
|
|
67
74
|
label: 'Handlers',
|
|
68
75
|
dataKey: 'handlers',
|
|
76
|
+
hideIf: (data) => data.autoDelegate,
|
|
69
77
|
},
|
|
70
78
|
{
|
|
71
79
|
type: 'graphSelector',
|
|
72
80
|
dataKey: 'unknownHandler',
|
|
73
81
|
label: 'Unknown Handler',
|
|
74
|
-
helperMessage: 'The subgraph to delegate to if the
|
|
82
|
+
helperMessage: 'The subgraph to delegate to if the tool call does not match any handlers.',
|
|
75
83
|
},
|
|
76
84
|
];
|
|
77
85
|
}
|
|
78
86
|
getBody(context) {
|
|
87
|
+
if (this.data.autoDelegate) {
|
|
88
|
+
return 'Auto Delegate To Subgraphs';
|
|
89
|
+
}
|
|
79
90
|
if (this.data.handlers.length === 0) {
|
|
80
91
|
return 'No handlers defined';
|
|
81
92
|
}
|
|
@@ -88,13 +99,27 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
88
99
|
}
|
|
89
100
|
async process(inputs, context) {
|
|
90
101
|
const functionCall = coerceType(inputs['function-call'], 'object');
|
|
91
|
-
let handler
|
|
102
|
+
let handler;
|
|
103
|
+
if (this.data.autoDelegate) {
|
|
104
|
+
const matchingGraph = Object.values(context.project.graphs).find((graph) => graph.metadata?.name?.includes(functionCall.name));
|
|
105
|
+
if (matchingGraph) {
|
|
106
|
+
handler = { key: undefined, value: matchingGraph.metadata.id };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
handler = this.data.handlers.find((handler) => handler.key === functionCall.name);
|
|
111
|
+
}
|
|
92
112
|
if (!handler) {
|
|
93
113
|
if (this.data.unknownHandler) {
|
|
94
114
|
handler = { key: undefined, value: this.data.unknownHandler };
|
|
95
115
|
}
|
|
96
116
|
else {
|
|
97
|
-
|
|
117
|
+
if (this.data.autoDelegate) {
|
|
118
|
+
throw new Error(`No handler found for tool call: ${functionCall.name}, no graph containing the name "${functionCall.name}" was found.`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
throw new Error(`No handler found for tool call: ${functionCall.name}`);
|
|
122
|
+
}
|
|
98
123
|
}
|
|
99
124
|
}
|
|
100
125
|
const subgraphInputs = {
|
|
@@ -107,7 +132,7 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
107
132
|
value: functionCall.arguments,
|
|
108
133
|
},
|
|
109
134
|
};
|
|
110
|
-
for (const [argName, argument] of Object.entries(functionCall.arguments)) {
|
|
135
|
+
for (const [argName, argument] of Object.entries(functionCall.arguments ?? {})) {
|
|
111
136
|
subgraphInputs[argName] = {
|
|
112
137
|
type: 'any',
|
|
113
138
|
value: argument,
|
|
@@ -133,4 +158,4 @@ export class DelegateFunctionCallNodeImpl extends NodeImpl {
|
|
|
133
158
|
};
|
|
134
159
|
}
|
|
135
160
|
}
|
|
136
|
-
export const delegateFunctionCallNode = nodeDefinition(DelegateFunctionCallNodeImpl, 'Delegate
|
|
161
|
+
export const delegateFunctionCallNode = nodeDefinition(DelegateFunctionCallNodeImpl, 'Delegate Tool Call');
|
|
@@ -35,7 +35,7 @@ export class DestructureNodeImpl extends NodeImpl {
|
|
|
35
35
|
];
|
|
36
36
|
}
|
|
37
37
|
getOutputDefinitions() {
|
|
38
|
-
return this.
|
|
38
|
+
return this.data.paths.map((path, index) => ({
|
|
39
39
|
id: `match_${index}`,
|
|
40
40
|
title: path,
|
|
41
41
|
dataType: 'any',
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {} from '../NodeBase.js';
|
|
2
|
+
import { NodeImpl } from '../NodeImpl.js';
|
|
3
|
+
import { nanoid } from 'nanoid/non-secure';
|
|
4
|
+
import {} from '../../index.js';
|
|
5
|
+
import { base64ToUint8Array, expectType } from '../../utils/index.js';
|
|
6
|
+
import { nodeDefinition } from '../NodeDefinition.js';
|
|
7
|
+
import { getInputOrData } from '../../utils/inputs.js';
|
|
8
|
+
import { dedent } from '../../utils/misc.js';
|
|
9
|
+
export class DocumentNodeImpl extends NodeImpl {
|
|
10
|
+
static create() {
|
|
11
|
+
return {
|
|
12
|
+
id: nanoid(),
|
|
13
|
+
type: 'document',
|
|
14
|
+
title: 'Document',
|
|
15
|
+
visualData: { x: 0, y: 0, width: 300 },
|
|
16
|
+
data: {
|
|
17
|
+
useDataInput: false,
|
|
18
|
+
useMediaTypeInput: false,
|
|
19
|
+
title: '',
|
|
20
|
+
useTitleInput: false,
|
|
21
|
+
context: '',
|
|
22
|
+
useContextInput: false,
|
|
23
|
+
enableCitations: false,
|
|
24
|
+
useEnableCitationsInput: false,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
getInputDefinitions() {
|
|
29
|
+
const inputDefinitions = [];
|
|
30
|
+
if (this.chartNode.data.useDataInput) {
|
|
31
|
+
inputDefinitions.push({
|
|
32
|
+
id: 'data',
|
|
33
|
+
title: 'Data',
|
|
34
|
+
dataType: ['string', 'binary'],
|
|
35
|
+
coerced: false,
|
|
36
|
+
description: 'The document data. Either string or binary data loaded from a file.',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (this.chartNode.data.useMediaTypeInput) {
|
|
40
|
+
inputDefinitions.push({
|
|
41
|
+
id: 'mediaType',
|
|
42
|
+
title: 'Media Type',
|
|
43
|
+
dataType: 'string',
|
|
44
|
+
coerced: false,
|
|
45
|
+
description: 'The media type of the document, such as text/plain or application/pdf.',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (this.data.useTitleInput) {
|
|
49
|
+
inputDefinitions.push({
|
|
50
|
+
id: 'title',
|
|
51
|
+
title: 'Title',
|
|
52
|
+
dataType: 'string',
|
|
53
|
+
coerced: true,
|
|
54
|
+
description: 'The title of the document.',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (this.data.useContextInput) {
|
|
58
|
+
inputDefinitions.push({
|
|
59
|
+
id: 'context',
|
|
60
|
+
title: 'Context',
|
|
61
|
+
dataType: 'string',
|
|
62
|
+
coerced: true,
|
|
63
|
+
description: 'The context of the document.',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (this.data.useEnableCitationsInput) {
|
|
67
|
+
inputDefinitions.push({
|
|
68
|
+
id: 'enableCitations',
|
|
69
|
+
title: 'Enable Citations',
|
|
70
|
+
dataType: 'boolean',
|
|
71
|
+
coerced: true,
|
|
72
|
+
description: 'Whether to enable citations for the document.',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return inputDefinitions;
|
|
76
|
+
}
|
|
77
|
+
getOutputDefinitions() {
|
|
78
|
+
return [
|
|
79
|
+
{
|
|
80
|
+
id: 'data',
|
|
81
|
+
title: 'Document Data',
|
|
82
|
+
dataType: 'document',
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
getEditors() {
|
|
87
|
+
return [
|
|
88
|
+
{
|
|
89
|
+
type: 'fileBrowser',
|
|
90
|
+
label: 'Document File',
|
|
91
|
+
dataKey: 'data',
|
|
92
|
+
mediaTypeDataKey: 'mediaType',
|
|
93
|
+
useInputToggleDataKey: 'useDataInput',
|
|
94
|
+
accept: '*/*',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: 'string',
|
|
98
|
+
label: 'Media Type',
|
|
99
|
+
dataKey: 'mediaType',
|
|
100
|
+
useInputToggleDataKey: 'useMediaTypeInput',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
type: 'string',
|
|
104
|
+
label: 'Title',
|
|
105
|
+
dataKey: 'title',
|
|
106
|
+
useInputToggleDataKey: 'useTitleInput',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
type: 'string',
|
|
110
|
+
label: 'Context',
|
|
111
|
+
dataKey: 'context',
|
|
112
|
+
useInputToggleDataKey: 'useContextInput',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: 'toggle',
|
|
116
|
+
label: 'Enable Citations',
|
|
117
|
+
dataKey: 'enableCitations',
|
|
118
|
+
useInputToggleDataKey: 'useEnableCitationsInput',
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
static getUIData() {
|
|
123
|
+
return {
|
|
124
|
+
contextMenuTitle: 'Document',
|
|
125
|
+
group: 'Data',
|
|
126
|
+
infoBoxTitle: 'Document Node',
|
|
127
|
+
infoBoxBody: 'Defines a document for use with other nodes such as Assemble Message. Can accept text and PDF files.',
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
getBody(_context) {
|
|
131
|
+
const parts = [
|
|
132
|
+
this.data.useDataInput ? '(Data from input)' : '(Data stored in node)',
|
|
133
|
+
this.data.useMediaTypeInput
|
|
134
|
+
? '(Media type from input)'
|
|
135
|
+
: this.data.mediaType
|
|
136
|
+
? `(${this.data.mediaType.trim()})`
|
|
137
|
+
: undefined,
|
|
138
|
+
this.data.useTitleInput ? '(Title from input)' : this.data.title ? `Title: ${this.data.title}` : undefined,
|
|
139
|
+
this.data.useContextInput
|
|
140
|
+
? '(Context from input)'
|
|
141
|
+
: this.data.context
|
|
142
|
+
? `Context: ${this.data.context}`
|
|
143
|
+
: undefined,
|
|
144
|
+
].filter((x) => x != null);
|
|
145
|
+
return dedent `
|
|
146
|
+
${parts.join('\n')}
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
async process(inputData, context) {
|
|
150
|
+
let data;
|
|
151
|
+
const mediaType = getInputOrData(this.data, inputData, 'mediaType', 'string') || 'text/plain';
|
|
152
|
+
const title = getInputOrData(this.data, inputData, 'title');
|
|
153
|
+
const contextInput = getInputOrData(this.data, inputData, 'context');
|
|
154
|
+
const enableCitations = getInputOrData(this.data, inputData, 'enableCitations', 'boolean');
|
|
155
|
+
if (this.chartNode.data.useDataInput) {
|
|
156
|
+
data = expectType(inputData['data'], 'binary');
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
const dataRef = this.data.data?.refId;
|
|
160
|
+
if (!dataRef) {
|
|
161
|
+
throw new Error('No data ref');
|
|
162
|
+
}
|
|
163
|
+
const encodedData = context.project.data?.[dataRef];
|
|
164
|
+
if (!encodedData) {
|
|
165
|
+
throw new Error(`No data at ref ${dataRef}`);
|
|
166
|
+
}
|
|
167
|
+
data = base64ToUint8Array(encodedData);
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
['data']: {
|
|
171
|
+
type: 'document',
|
|
172
|
+
value: {
|
|
173
|
+
data,
|
|
174
|
+
mediaType: mediaType,
|
|
175
|
+
title,
|
|
176
|
+
context: contextInput,
|
|
177
|
+
enableCitations,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export const documentNode = nodeDefinition(DocumentNodeImpl, 'Document');
|
|
@@ -76,10 +76,10 @@ export class ExtractJsonNodeImpl extends NodeImpl {
|
|
|
76
76
|
// Fall back to more manual parsing
|
|
77
77
|
}
|
|
78
78
|
// Find the first { or [ and the last } or ], and try parsing everything in between including them.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
const firstBracket = inputString.indexOf('{');
|
|
80
|
+
const lastBracket = inputString.lastIndexOf('}');
|
|
81
|
+
const firstSquareBracket = inputString.indexOf('[');
|
|
82
|
+
const lastSquareBracket = inputString.lastIndexOf(']');
|
|
83
83
|
const firstIndex = firstBracket >= 0 && firstSquareBracket >= 0
|
|
84
84
|
? Math.min(firstBracket, firstSquareBracket)
|
|
85
85
|
: firstBracket >= 0
|