@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.
Files changed (105) hide show
  1. package/README.md +4 -0
  2. package/dist/cjs/bundle.cjs +3993 -943
  3. package/dist/cjs/bundle.cjs.map +4 -4
  4. package/dist/esm/api/createProcessor.js +8 -17
  5. package/dist/esm/api/looseDataValue.js +16 -0
  6. package/dist/esm/exports.js +2 -0
  7. package/dist/esm/integrations/CodeRunner.js +36 -0
  8. package/dist/esm/integrations/GptTokenizerTokenizer.js +7 -4
  9. package/dist/esm/integrations/openai/OpenAIEmbeddingGenerator.js +1 -1
  10. package/dist/esm/model/DataValue.js +14 -2
  11. package/dist/esm/model/GraphProcessor.js +275 -104
  12. package/dist/esm/model/NodeBase.js +11 -1
  13. package/dist/esm/model/NodeImpl.js +8 -0
  14. package/dist/esm/model/Nodes.js +28 -4
  15. package/dist/esm/model/ProjectReferenceLoader.js +1 -0
  16. package/dist/esm/model/nodes/AssembleMessageNode.js +12 -2
  17. package/dist/esm/model/nodes/AssemblePromptNode.js +22 -0
  18. package/dist/esm/model/nodes/CallGraphNode.js +3 -4
  19. package/dist/esm/model/nodes/ChatLoopNode.js +150 -0
  20. package/dist/esm/model/nodes/ChatNode.js +7 -934
  21. package/dist/esm/model/nodes/ChatNodeBase.js +1275 -0
  22. package/dist/esm/model/nodes/ChunkNode.js +2 -2
  23. package/dist/esm/model/nodes/CodeNode.js +40 -4
  24. package/dist/esm/model/nodes/CronNode.js +248 -0
  25. package/dist/esm/model/nodes/DelegateFunctionCallNode.js +37 -12
  26. package/dist/esm/model/nodes/DestructureNode.js +1 -1
  27. package/dist/esm/model/nodes/DocumentNode.js +183 -0
  28. package/dist/esm/model/nodes/ExtractJsonNode.js +4 -4
  29. package/dist/esm/model/nodes/ExtractRegexNode.js +10 -11
  30. package/dist/esm/model/nodes/GetEmbeddingNode.js +1 -1
  31. package/dist/esm/model/nodes/HttpCallNode.js +3 -1
  32. package/dist/esm/model/nodes/IfNode.js +5 -0
  33. package/dist/esm/model/nodes/LoopUntilNode.js +214 -0
  34. package/dist/esm/model/nodes/PromptNode.js +29 -6
  35. package/dist/esm/model/nodes/ReadAllFilesNode.js +210 -0
  36. package/dist/esm/model/nodes/ReadDirectoryNode.js +31 -25
  37. package/dist/esm/model/nodes/ReferencedGraphAliasNode.js +199 -0
  38. package/dist/esm/model/nodes/TextNode.js +9 -4
  39. package/dist/esm/model/nodes/ToMarkdownTableNode.js +119 -0
  40. package/dist/esm/model/nodes/ToTreeNode.js +133 -0
  41. package/dist/esm/model/nodes/{GptFunctionNode.js → ToolNode.js} +10 -10
  42. package/dist/esm/model/nodes/UserInputNode.js +10 -12
  43. package/dist/esm/plugins/aidon/nodes/ChatAidonNode.js +2 -2
  44. package/dist/esm/plugins/anthropic/anthropic.js +29 -10
  45. package/dist/esm/plugins/anthropic/fetchEventSource.js +3 -2
  46. package/dist/esm/plugins/anthropic/nodes/ChatAnthropicNode.js +267 -147
  47. package/dist/esm/plugins/anthropic/plugin.js +9 -1
  48. package/dist/esm/plugins/gentrace/plugin.js +6 -6
  49. package/dist/esm/plugins/google/google.js +113 -5
  50. package/dist/esm/plugins/google/nodes/ChatGoogleNode.js +211 -54
  51. package/dist/esm/plugins/google/plugin.js +13 -6
  52. package/dist/esm/plugins/openai/nodes/RunThreadNode.js +2 -2
  53. package/dist/esm/recording/ExecutionRecorder.js +5 -1
  54. package/dist/esm/utils/chatMessageToOpenAIChatCompletionMessage.js +15 -2
  55. package/dist/esm/utils/coerceType.js +1 -1
  56. package/dist/esm/utils/fetchEventSource.js +1 -1
  57. package/dist/esm/utils/interpolation.js +108 -3
  58. package/dist/esm/utils/openai.js +106 -50
  59. package/dist/esm/utils/paths.js +80 -0
  60. package/dist/esm/utils/serialization/serialization_v4.js +5 -0
  61. package/dist/types/api/createProcessor.d.ts +11 -5
  62. package/dist/types/api/looseDataValue.d.ts +4 -0
  63. package/dist/types/api/streaming.d.ts +1 -1
  64. package/dist/types/exports.d.ts +2 -0
  65. package/dist/types/integrations/CodeRunner.d.ts +18 -0
  66. package/dist/types/model/DataValue.d.ts +29 -6
  67. package/dist/types/model/EditorDefinition.d.ts +6 -1
  68. package/dist/types/model/GraphProcessor.d.ts +14 -7
  69. package/dist/types/model/NodeBase.d.ts +4 -0
  70. package/dist/types/model/NodeImpl.d.ts +5 -4
  71. package/dist/types/model/Nodes.d.ts +12 -4
  72. package/dist/types/model/ProcessContext.d.ts +16 -1
  73. package/dist/types/model/Project.d.ts +19 -7
  74. package/dist/types/model/ProjectReferenceLoader.d.ts +5 -0
  75. package/dist/types/model/RivetPlugin.d.ts +6 -0
  76. package/dist/types/model/RivetUIContext.d.ts +5 -1
  77. package/dist/types/model/Settings.d.ts +1 -0
  78. package/dist/types/model/nodes/AssemblePromptNode.d.ts +4 -1
  79. package/dist/types/model/nodes/ChatLoopNode.d.ts +21 -0
  80. package/dist/types/model/nodes/ChatNode.d.ts +2 -62
  81. package/dist/types/model/nodes/ChatNodeBase.d.ts +85 -0
  82. package/dist/types/model/nodes/CodeNode.d.ts +8 -2
  83. package/dist/types/model/nodes/CronNode.d.ts +34 -0
  84. package/dist/types/model/nodes/DelegateFunctionCallNode.d.ts +1 -0
  85. package/dist/types/model/nodes/DocumentNode.d.ts +28 -0
  86. package/dist/types/model/nodes/LoopUntilNode.d.ts +32 -0
  87. package/dist/types/model/nodes/PromptNode.d.ts +2 -0
  88. package/dist/types/model/nodes/ReadAllFilesNode.d.ts +30 -0
  89. package/dist/types/model/nodes/ReadDirectoryNode.d.ts +1 -1
  90. package/dist/types/model/nodes/ReferencedGraphAliasNode.d.ts +31 -0
  91. package/dist/types/model/nodes/ToMarkdownTableNode.d.ts +19 -0
  92. package/dist/types/model/nodes/ToTreeNode.d.ts +21 -0
  93. package/dist/types/model/nodes/UserInputNode.d.ts +2 -3
  94. package/dist/types/plugins/anthropic/anthropic.d.ts +94 -13
  95. package/dist/types/plugins/anthropic/nodes/ChatAnthropicNode.d.ts +7 -2
  96. package/dist/types/plugins/google/google.d.ts +93 -18
  97. package/dist/types/plugins/google/nodes/ChatGoogleNode.d.ts +3 -2
  98. package/dist/types/recording/RecordedEvents.d.ts +2 -0
  99. package/dist/types/utils/base64.d.ts +1 -1
  100. package/dist/types/utils/chatMessageToOpenAIChatCompletionMessage.d.ts +3 -1
  101. package/dist/types/utils/interpolation.d.ts +3 -0
  102. package/dist/types/utils/openai.d.ts +127 -21
  103. package/dist/types/utils/paths.d.ts +8 -0
  104. package/package.json +15 -11
  105. /package/dist/types/model/nodes/{GptFunctionNode.d.ts → ToolNode.d.ts} +0 -0
@@ -6,7 +6,8 @@ import {} from '../GraphProcessor.js';
6
6
  import {} from '../../index.js';
7
7
  import {} from '../ProcessContext.js';
8
8
  import { dedent } from 'ts-dedent';
9
- import { expectType } from '../../utils/expectType.js';
9
+ import { createTreeFromPaths } from '../../utils/paths.js';
10
+ import { getInputOrData } from '../../utils/inputs.js';
10
11
  export class ReadDirectoryNodeImpl extends NodeImpl {
11
12
  static create() {
12
13
  return {
@@ -91,6 +92,11 @@ export class ReadDirectoryNodeImpl extends NodeImpl {
91
92
  title: 'Paths',
92
93
  dataType: 'string[]',
93
94
  },
95
+ {
96
+ id: 'tree',
97
+ title: 'Tree',
98
+ dataType: 'object',
99
+ },
94
100
  ];
95
101
  }
96
102
  getBody() {
@@ -109,36 +115,27 @@ export class ReadDirectoryNodeImpl extends NodeImpl {
109
115
  static getUIData() {
110
116
  return {
111
117
  infoBoxBody: dedent `
112
- Reads the contents of the specified directory and outputs an array of filenames.
118
+ Reads the contents of the specified directory and outputs:
119
+ 1. An array of filenames
120
+ 2. The root path of the search
121
+ 3. A tree structure representing the directory hierarchy
113
122
  `,
114
123
  infoBoxTitle: 'Read Directory Node',
115
124
  contextMenuTitle: 'Read Directory',
116
125
  group: ['Input/Output'],
117
126
  };
118
127
  }
119
- async process(inputData, context) {
128
+ async process(inputs, context) {
120
129
  const { nativeApi } = context;
121
130
  if (nativeApi == null) {
122
131
  throw new Error('This node requires a native API to run.');
123
132
  }
124
- const path = this.chartNode.data.usePathInput
125
- ? expectType(inputData['path'], 'string')
126
- : this.chartNode.data.path;
127
- const recursive = this.chartNode.data.useRecursiveInput
128
- ? expectType(inputData['recursive'], 'boolean')
129
- : this.chartNode.data.recursive;
130
- const includeDirectories = this.chartNode.data.useIncludeDirectoriesInput
131
- ? expectType(inputData['includeDirectories'], 'boolean')
132
- : this.chartNode.data.includeDirectories;
133
- const filterGlobs = this.chartNode.data.useFilterGlobsInput
134
- ? expectType(inputData['filterGlobs'], 'string[]')
135
- : this.chartNode.data.filterGlobs;
136
- const relative = this.chartNode.data.useRelativeInput
137
- ? expectType(inputData['relative'], 'boolean')
138
- : this.chartNode.data.relative;
139
- const ignores = this.chartNode.data.useIgnoresInput
140
- ? expectType(inputData['ignores'], 'string[]')
141
- : this.chartNode.data.ignores;
133
+ const path = getInputOrData(this.data, inputs, 'path');
134
+ const recursive = getInputOrData(this.data, inputs, 'recursive', 'boolean');
135
+ const includeDirectories = getInputOrData(this.data, inputs, 'includeDirectories', 'boolean');
136
+ const filterGlobs = getInputOrData(this.data, inputs, 'filterGlobs', 'string[]');
137
+ const relative = getInputOrData(this.data, inputs, 'relative', 'boolean');
138
+ const ignores = getInputOrData(this.data, inputs, 'ignores', 'string[]');
142
139
  try {
143
140
  const files = await nativeApi.readdir(path, undefined, {
144
141
  recursive,
@@ -147,18 +144,27 @@ export class ReadDirectoryNodeImpl extends NodeImpl {
147
144
  relative,
148
145
  ignores,
149
146
  });
150
- const outputs = {
147
+ const tree = createTreeFromPaths(files, path);
148
+ return {
151
149
  ['paths']: { type: 'string[]', value: files },
152
150
  ['rootPath']: { type: 'string', value: path },
151
+ ['tree']: { type: 'object', value: tree },
153
152
  };
154
- return outputs;
155
153
  }
156
154
  catch (err) {
157
- const outputs = {
155
+ return {
158
156
  ['paths']: { type: 'string[]', value: ['(no such path)'] },
159
157
  ['rootPath']: { type: 'string', value: path },
158
+ ['tree']: {
159
+ type: 'object',
160
+ value: {
161
+ path,
162
+ name: path.split('/').pop() || path,
163
+ isDirectory: true,
164
+ children: [],
165
+ },
166
+ },
160
167
  };
161
- return outputs;
162
168
  }
163
169
  }
164
170
  }
@@ -0,0 +1,199 @@
1
+ import {} from '../NodeBase.js';
2
+ import { NodeImpl } from '../NodeImpl.js';
3
+ import { nodeDefinition } from '../NodeDefinition.js';
4
+ import {} from '../GraphProcessor.js';
5
+ import {} from '../NodeGraph.js';
6
+ import { nanoid } from 'nanoid/non-secure';
7
+ import {} from '../Project.js';
8
+ import {} from './GraphInputNode.js';
9
+ import {} from './GraphOutputNode.js';
10
+ import {} from '../DataValue.js';
11
+ import {} from '../ProcessContext.js';
12
+ import { dedent } from 'ts-dedent';
13
+ import { getError } from '../../utils/errors.js';
14
+ export class ReferencedGraphAliasNodeImpl extends NodeImpl {
15
+ static create() {
16
+ const chartNode = {
17
+ type: 'referencedGraphAlias',
18
+ title: '', // Always set initially by the editor
19
+ id: nanoid(),
20
+ visualData: {
21
+ x: 0,
22
+ y: 0,
23
+ width: 300,
24
+ },
25
+ data: {
26
+ projectId: undefined, // Always set initially by the editor
27
+ graphId: undefined, // Always set initially by the editor
28
+ useErrorOutput: false,
29
+ },
30
+ };
31
+ return chartNode;
32
+ }
33
+ getInputDefinitions(_connections, _nodes, _project, referencedProjects) {
34
+ const referencedProject = referencedProjects[this.data.projectId];
35
+ if (!referencedProject) {
36
+ return [];
37
+ }
38
+ const graph = referencedProject.graphs[this.data.graphId];
39
+ if (!graph) {
40
+ return [];
41
+ }
42
+ const inputNodes = graph.nodes.filter((node) => node.type === 'graphInput');
43
+ const inputIds = [...new Set(inputNodes.map((node) => node.data.id))].sort();
44
+ return inputIds.map((id) => ({
45
+ id: id,
46
+ title: id,
47
+ dataType: inputNodes.find((node) => node.data.id === id).data.dataType,
48
+ }));
49
+ }
50
+ getGraphOutputs(referencedProject) {
51
+ const graph = referencedProject.graphs[this.data.graphId];
52
+ if (!graph) {
53
+ return [];
54
+ }
55
+ const outputNodes = graph.nodes.filter((node) => node.type === 'graphOutput');
56
+ const outputIds = [...new Set(outputNodes.map((node) => node.data.id))].sort();
57
+ const outputs = outputIds.map((id) => ({
58
+ id: id,
59
+ title: id,
60
+ dataType: outputNodes.find((node) => node.data.id === id).data.dataType,
61
+ }));
62
+ return outputs;
63
+ }
64
+ getOutputDefinitions(_connections, _nodes, _project, referencedProjects) {
65
+ const outputs = [];
66
+ const referencedProject = referencedProjects[this.data.projectId];
67
+ if (!referencedProject) {
68
+ return outputs;
69
+ }
70
+ outputs.push(...this.getGraphOutputs(referencedProject));
71
+ if (this.data.useErrorOutput) {
72
+ outputs.push({
73
+ id: 'error',
74
+ title: 'Error',
75
+ dataType: 'string',
76
+ });
77
+ }
78
+ return outputs;
79
+ }
80
+ getEditors(context) {
81
+ const definitions = [
82
+ {
83
+ type: 'toggle',
84
+ label: 'Use Error Output',
85
+ dataKey: 'useErrorOutput',
86
+ },
87
+ {
88
+ type: 'toggle',
89
+ label: 'Output Cost & Duration',
90
+ dataKey: 'outputCostDuration',
91
+ },
92
+ ];
93
+ const referencedProject = context.referencedProjects[this.data.projectId];
94
+ if (referencedProject) {
95
+ const graph = referencedProject.graphs[this.data.graphId];
96
+ if (graph) {
97
+ const inputNodes = graph.nodes.filter((node) => node.type === 'graphInput');
98
+ const inputIds = [...new Set(inputNodes.map((node) => node.data.id))].sort();
99
+ for (const inputId of inputIds) {
100
+ const inputNode = inputNodes.find((node) => node.data.id === inputId);
101
+ definitions.push({
102
+ type: 'dynamic',
103
+ dataKey: 'inputData',
104
+ dynamicDataKey: inputNode.data.id,
105
+ dataType: inputNode.data.dataType,
106
+ label: inputNode.data.id,
107
+ editor: inputNode.data.editor ?? 'auto',
108
+ });
109
+ }
110
+ }
111
+ }
112
+ return definitions;
113
+ }
114
+ getBody(context) {
115
+ return context.referencedProjects[this.data.projectId]?.graphs[this.data.graphId]?.metadata?.description ?? '';
116
+ }
117
+ static getUIData() {
118
+ return {
119
+ infoBoxBody: dedent `
120
+ References a graph from another project. Inputs and outputs are defined by Graph Input and Graph Output nodes within the referenced graph.
121
+ `,
122
+ infoBoxTitle: 'Referenced Graph Alias Node',
123
+ contextMenuTitle: 'Referenced Graph Alias',
124
+ group: ['Advanced'],
125
+ };
126
+ }
127
+ async process(inputs, context) {
128
+ const referencedProject = context.referencedProjects[this.data.projectId];
129
+ if (!referencedProject) {
130
+ throw new Error(`ReferencedGraphAliasNode requires a project with id ${this.data.projectId} to be available in the context.referencedProjects.`);
131
+ }
132
+ const graph = referencedProject.graphs[this.data.graphId];
133
+ if (!graph) {
134
+ throw new Error(`ReferencedGraphAliasNode requires a graph with id ${this.data.graphId} to be present in the referenced project.`);
135
+ }
136
+ const inputNodes = graph.nodes.filter((node) => node.type === 'graphInput');
137
+ const inputIds = [...new Set(inputNodes.map((node) => node.data.id))].sort();
138
+ const inputData = inputIds.reduce((obj, id) => {
139
+ if (inputs[id] != null) {
140
+ return {
141
+ ...obj,
142
+ [id]: inputs[id],
143
+ };
144
+ }
145
+ if (this.data.inputData?.[id] != null) {
146
+ return {
147
+ ...obj,
148
+ [id]: this.data.inputData[id],
149
+ };
150
+ }
151
+ return obj;
152
+ }, {});
153
+ // Create a subprocessor using the referenced project's graph
154
+ const subGraphProcessor = context.createSubProcessor(this.data.graphId, {
155
+ signal: context.signal,
156
+ project: referencedProject,
157
+ });
158
+ try {
159
+ const startTime = Date.now();
160
+ const outputs = await subGraphProcessor.processGraph(context, inputData, context.contextValues);
161
+ const duration = Date.now() - startTime;
162
+ if (this.data.useErrorOutput) {
163
+ outputs['error'] = {
164
+ type: 'control-flow-excluded',
165
+ value: undefined,
166
+ };
167
+ }
168
+ if (outputs['duration'] == null) {
169
+ outputs['duration'] = {
170
+ type: 'number',
171
+ value: duration,
172
+ };
173
+ }
174
+ if (!this.data.outputCostDuration) {
175
+ delete outputs['cost'];
176
+ delete outputs['duration'];
177
+ }
178
+ return outputs;
179
+ }
180
+ catch (err) {
181
+ if (!this.data.useErrorOutput) {
182
+ throw err;
183
+ }
184
+ const outputs = this.getGraphOutputs(referencedProject).reduce((obj, output) => ({
185
+ ...obj,
186
+ [output.id]: {
187
+ type: 'control-flow-excluded',
188
+ value: undefined,
189
+ },
190
+ }), {});
191
+ outputs['error'] = {
192
+ type: 'string',
193
+ value: getError(err).message,
194
+ };
195
+ return outputs;
196
+ }
197
+ }
198
+ }
199
+ export const referencedGraphAliasNode = nodeDefinition(ReferencedGraphAliasNodeImpl, 'Referenced Graph Alias');
@@ -6,7 +6,7 @@ import {} from '../DataValue.js';
6
6
  import {} from '../../index.js';
7
7
  import { dedent } from 'ts-dedent';
8
8
  import { coerceTypeOptional } from '../../utils/coerceType.js';
9
- import { interpolate } from '../../utils/interpolation.js';
9
+ import { extractInterpolationVariables, interpolate } from '../../utils/interpolation.js';
10
10
  export class TextNodeImpl extends NodeImpl {
11
11
  static create() {
12
12
  const chartNode = {
@@ -26,13 +26,13 @@ export class TextNodeImpl extends NodeImpl {
26
26
  }
27
27
  getInputDefinitions() {
28
28
  // Extract inputs from text, everything like {{input}}
29
- const inputNames = [...new Set(this.chartNode.data.text.match(/\{\{([^}]+)\}\}/g))];
29
+ const inputNames = extractInterpolationVariables(this.data.text);
30
30
  return (inputNames?.map((inputName) => {
31
31
  return {
32
32
  type: 'string',
33
33
  // id and title should not have the {{ and }}
34
- id: inputName.slice(2, -2),
35
- title: inputName.slice(2, -2),
34
+ id: inputName,
35
+ title: inputName,
36
36
  dataType: 'string',
37
37
  required: false,
38
38
  };
@@ -49,6 +49,11 @@ export class TextNodeImpl extends NodeImpl {
49
49
  }
50
50
  getEditors() {
51
51
  return [
52
+ {
53
+ type: 'custom',
54
+ label: 'AI Assist',
55
+ customEditorId: 'TextNodeAiAssist',
56
+ },
52
57
  {
53
58
  type: 'code',
54
59
  label: 'Text',
@@ -0,0 +1,119 @@
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 {} from '../../index.js';
7
+ import { dedent } from 'ts-dedent';
8
+ import { coerceType } from '../../utils/coerceType.js';
9
+ export class ToMarkdownTableNodeImpl extends NodeImpl {
10
+ static create() {
11
+ const chartNode = {
12
+ type: 'toMarkdownTable',
13
+ title: 'To Markdown Table',
14
+ id: nanoid(),
15
+ visualData: {
16
+ x: 0,
17
+ y: 0,
18
+ width: 200,
19
+ },
20
+ data: {
21
+ includeHeaders: true,
22
+ alignPipes: false,
23
+ },
24
+ };
25
+ return chartNode;
26
+ }
27
+ getInputDefinitions() {
28
+ return [
29
+ {
30
+ id: 'data',
31
+ title: 'Data Array',
32
+ dataType: 'any',
33
+ required: true,
34
+ },
35
+ ];
36
+ }
37
+ getOutputDefinitions() {
38
+ return [
39
+ {
40
+ id: 'markdown',
41
+ title: 'Markdown Table',
42
+ dataType: 'string',
43
+ },
44
+ ];
45
+ }
46
+ getEditors() {
47
+ return [
48
+ {
49
+ type: 'toggle',
50
+ label: 'Include Headers',
51
+ dataKey: 'includeHeaders',
52
+ },
53
+ {
54
+ type: 'toggle',
55
+ label: 'Align Pipes',
56
+ dataKey: 'alignPipes',
57
+ },
58
+ ];
59
+ }
60
+ getBody() {
61
+ const parts = [];
62
+ if (this.data.includeHeaders)
63
+ parts.push('With Header Row');
64
+ if (this.data.alignPipes)
65
+ parts.push('Pipes Aligned');
66
+ return parts.length > 0 ? parts.join(', ') : undefined;
67
+ }
68
+ static getUIData() {
69
+ return {
70
+ infoBoxBody: dedent `
71
+ Converts an array of objects into a markdown table format.
72
+ Input should be an array of objects with consistent keys.
73
+ `,
74
+ infoBoxTitle: 'To Markdown Table Node',
75
+ contextMenuTitle: 'To Markdown Table',
76
+ group: ['Text'],
77
+ };
78
+ }
79
+ async process(inputs) {
80
+ const data = coerceType(inputs['data'], 'object[]');
81
+ const keys = data.length === 0 ? [] : Object.keys(data[0]);
82
+ // Dynamic import because these are ESM-only, and top level imports are converted to CommonJS for rivet-node.
83
+ // Dynamic import is able to load ESM-only modules.
84
+ const { toMarkdown } = await import('mdast-util-to-markdown');
85
+ const { gfmTableToMarkdown } = await import('mdast-util-gfm-table');
86
+ const markdownTable = toMarkdown({
87
+ type: 'table',
88
+ children: [
89
+ ...(this.data.includeHeaders
90
+ ? [
91
+ {
92
+ type: 'tableRow',
93
+ children: keys.map((key) => ({
94
+ type: 'tableCell',
95
+ children: [{ type: 'text', value: key }],
96
+ })),
97
+ },
98
+ ]
99
+ : []),
100
+ ...data.map((row) => ({
101
+ type: 'tableRow',
102
+ children: keys.map((key) => ({
103
+ type: 'tableCell',
104
+ children: [{ type: 'text', value: `${row[key]}` }],
105
+ })),
106
+ })),
107
+ ],
108
+ }, {
109
+ extensions: [gfmTableToMarkdown({ tablePipeAlign: this.data.alignPipes })],
110
+ });
111
+ return {
112
+ ['markdown']: {
113
+ type: 'string',
114
+ value: markdownTable,
115
+ },
116
+ };
117
+ }
118
+ }
119
+ export const toMarkdownTableNode = nodeDefinition(ToMarkdownTableNodeImpl, 'To Markdown Table');
@@ -0,0 +1,133 @@
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 '../DataValue.js';
6
+ import {} from '../EditorDefinition.js';
7
+ import { dedent } from 'ts-dedent';
8
+ import { coerceTypeOptional } from '../../utils/coerceType.js';
9
+ import { extractInterpolationVariables, interpolate } from '../../utils/interpolation.js';
10
+ import { get, sortBy } from 'lodash-es';
11
+ export class ToTreeNodeImpl extends NodeImpl {
12
+ static create() {
13
+ const chartNode = {
14
+ type: 'toTree',
15
+ title: 'To Tree',
16
+ id: nanoid(),
17
+ visualData: {
18
+ x: 0,
19
+ y: 0,
20
+ width: 300,
21
+ },
22
+ data: {
23
+ format: '{{path}}',
24
+ childrenProperty: 'children',
25
+ useSortAlphabetically: true,
26
+ },
27
+ };
28
+ return chartNode;
29
+ }
30
+ getInputDefinitions() {
31
+ return [
32
+ {
33
+ id: 'objects',
34
+ title: 'Objects',
35
+ dataType: ['object[]', 'object'],
36
+ required: true,
37
+ },
38
+ ];
39
+ }
40
+ getOutputDefinitions() {
41
+ return [
42
+ {
43
+ id: 'tree',
44
+ title: 'Tree',
45
+ dataType: 'string',
46
+ },
47
+ ];
48
+ }
49
+ getEditors() {
50
+ return [
51
+ {
52
+ type: 'string',
53
+ label: 'Children Property',
54
+ dataKey: 'childrenProperty',
55
+ },
56
+ {
57
+ type: 'code',
58
+ label: 'Format',
59
+ dataKey: 'format',
60
+ language: 'prompt-interpolation-markdown',
61
+ theme: 'prompt-interpolation',
62
+ },
63
+ {
64
+ type: 'toggle',
65
+ label: 'Sort Alphabetically',
66
+ dataKey: 'useSortAlphabetically',
67
+ },
68
+ ];
69
+ }
70
+ getBody() {
71
+ return dedent `
72
+ Format: ${this.data.format}
73
+ Children: ${this.data.childrenProperty}
74
+ Sort: ${this.data.useSortAlphabetically ? 'Yes' : 'No'}
75
+ `;
76
+ }
77
+ static getUIData() {
78
+ return {
79
+ infoBoxBody: dedent `
80
+ Converts an array of objects into a tree structure and renders it as text.
81
+
82
+ The format field supports interpolation using {{property}} syntax to determine
83
+ how each node is displayed.
84
+
85
+ Use the children property to specify which field contains child nodes.
86
+ `,
87
+ infoBoxTitle: 'To Tree Node',
88
+ contextMenuTitle: 'To Tree',
89
+ group: ['Text'],
90
+ };
91
+ }
92
+ buildTree(objects, parentPath = '', level = 0, isLast = true) {
93
+ if (!Array.isArray(objects) || objects.length === 0)
94
+ return '';
95
+ let result = '';
96
+ const sortedObjects = this.data.useSortAlphabetically
97
+ ? sortBy(objects, (obj) => String(get(obj, 'path', '')))
98
+ : objects;
99
+ sortedObjects.forEach((obj, index) => {
100
+ const isLastItem = index === sortedObjects.length - 1;
101
+ const prefix = level === 0 ? '' : isLast ? '└── ' : '├── ';
102
+ const indent = level === 0 ? '' : ' '.repeat(level - 1) + (isLast ? ' ' : '│ ');
103
+ // Get all potential interpolation variables from the format string
104
+ const matches = extractInterpolationVariables(this.data.format);
105
+ const interpolationVars = matches.reduce((acc, match) => {
106
+ const key = match;
107
+ acc[key] = String(get(obj, key, ''));
108
+ return acc;
109
+ }, {});
110
+ const formattedNode = interpolate(this.data.format, interpolationVars);
111
+ // Add this node to the result
112
+ result += indent + prefix + formattedNode + '\n';
113
+ // Process children if they exist
114
+ const children = get(obj, this.data.childrenProperty);
115
+ if (Array.isArray(children) && children.length > 0) {
116
+ const newPath = parentPath ? `${parentPath}/${formattedNode}` : formattedNode;
117
+ result += this.buildTree(children, newPath, level + 1, isLastItem);
118
+ }
119
+ });
120
+ return result;
121
+ }
122
+ async process(inputs) {
123
+ const objects = coerceTypeOptional(inputs['objects'], 'object[]') ?? [];
124
+ const treeOutput = this.buildTree(objects);
125
+ return {
126
+ ['tree']: {
127
+ type: 'string',
128
+ value: treeOutput,
129
+ },
130
+ };
131
+ }
132
+ }
133
+ export const toTreeNode = nodeDefinition(ToTreeNodeImpl, 'To Tree');
@@ -13,7 +13,7 @@ export class GptFunctionNodeImpl extends NodeImpl {
13
13
  static create() {
14
14
  const chartNode = {
15
15
  type: 'gptFunction',
16
- title: 'GPT Function',
16
+ title: 'Tool',
17
17
  id: nanoid(),
18
18
  visualData: {
19
19
  x: 0,
@@ -21,7 +21,7 @@ export class GptFunctionNodeImpl extends NodeImpl {
21
21
  width: 250,
22
22
  },
23
23
  data: {
24
- name: 'newFunction',
24
+ name: 'newTool',
25
25
  description: 'No description provided',
26
26
  schema: dedent `
27
27
  {
@@ -39,7 +39,7 @@ export class GptFunctionNodeImpl extends NodeImpl {
39
39
  id: 'name',
40
40
  title: 'Name',
41
41
  dataType: 'string',
42
- description: 'The name of the function that GPT will see as available to call',
42
+ description: 'The name of the tool that the LLM will see as available to call',
43
43
  });
44
44
  }
45
45
  if (this.data.useDescriptionInput) {
@@ -47,7 +47,7 @@ export class GptFunctionNodeImpl extends NodeImpl {
47
47
  id: 'description',
48
48
  title: 'Description',
49
49
  dataType: 'string',
50
- description: 'The description of the function that GPT will see as available to call',
50
+ description: 'The description of the tool that the LLM will see as available to call',
51
51
  });
52
52
  }
53
53
  if (this.data.useSchemaInput) {
@@ -55,7 +55,7 @@ export class GptFunctionNodeImpl extends NodeImpl {
55
55
  id: 'schema',
56
56
  title: 'Schema',
57
57
  dataType: 'object',
58
- description: 'The schema of the function that GPT will see as available to call',
58
+ description: 'The schema of the tool that the LLM will see as available to call',
59
59
  });
60
60
  }
61
61
  // Extract inputs from promptText, everything like {{input}}
@@ -81,7 +81,7 @@ export class GptFunctionNodeImpl extends NodeImpl {
81
81
  id: 'function',
82
82
  title: 'Function',
83
83
  dataType: 'gpt-function',
84
- description: 'The GPT function that can be called by the LLM.',
84
+ description: 'The tool that can be called by the LLM.',
85
85
  },
86
86
  ];
87
87
  }
@@ -127,10 +127,10 @@ export class GptFunctionNodeImpl extends NodeImpl {
127
127
  static getUIData() {
128
128
  return {
129
129
  infoBoxBody: dedent `
130
- Defines a GPT function, which is a method that the LLM can call in its responses.
130
+ Defines a tool, which is a method that the LLM can call in its responses.
131
131
  `,
132
- infoBoxTitle: 'GPT Function Node',
133
- contextMenuTitle: 'GPT Function',
132
+ infoBoxTitle: 'Tool Node',
133
+ contextMenuTitle: 'Tool',
134
134
  group: ['AI'],
135
135
  };
136
136
  }
@@ -166,4 +166,4 @@ export class GptFunctionNodeImpl extends NodeImpl {
166
166
  };
167
167
  }
168
168
  }
169
- export const gptFunctionNode = nodeDefinition(GptFunctionNodeImpl, 'GPT Function');
169
+ export const gptFunctionNode = nodeDefinition(GptFunctionNodeImpl, 'Tool');