@alpic80/rivet-core 1.19.1-aidon.3 → 1.24.0-aidon.3

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 (129) hide show
  1. package/README.md +4 -0
  2. package/dist/cjs/bundle.cjs +4512 -1240
  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/DatasetProvider.js +1 -1
  9. package/dist/esm/integrations/GptTokenizerTokenizer.js +7 -4
  10. package/dist/esm/integrations/openai/OpenAIEmbeddingGenerator.js +1 -1
  11. package/dist/esm/model/DataValue.js +14 -2
  12. package/dist/esm/model/GraphProcessor.js +276 -107
  13. package/dist/esm/model/NodeBase.js +11 -1
  14. package/dist/esm/model/NodeImpl.js +8 -0
  15. package/dist/esm/model/Nodes.js +31 -4
  16. package/dist/esm/model/ProjectReferenceLoader.js +1 -0
  17. package/dist/esm/model/nodes/AssembleMessageNode.js +12 -2
  18. package/dist/esm/model/nodes/AssemblePromptNode.js +22 -0
  19. package/dist/esm/model/nodes/CallGraphNode.js +3 -4
  20. package/dist/esm/model/nodes/ChatLoopNode.js +150 -0
  21. package/dist/esm/model/nodes/ChatNode.js +7 -934
  22. package/dist/esm/model/nodes/ChatNodeBase.js +1277 -0
  23. package/dist/esm/model/nodes/ChunkNode.js +2 -2
  24. package/dist/esm/model/nodes/CodeNode.js +40 -5
  25. package/dist/esm/model/nodes/CronNode.js +248 -0
  26. package/dist/esm/model/nodes/DelegateFunctionCallNode.js +37 -12
  27. package/dist/esm/model/nodes/DestructureNode.js +1 -1
  28. package/dist/esm/model/nodes/DocumentNode.js +183 -0
  29. package/dist/esm/model/nodes/ExtractJsonNode.js +4 -4
  30. package/dist/esm/model/nodes/ExtractRegexNode.js +10 -11
  31. package/dist/esm/model/nodes/GetAllDatasetsNode.js +1 -1
  32. package/dist/esm/model/nodes/GetEmbeddingNode.js +1 -1
  33. package/dist/esm/model/nodes/HttpCallNode.js +3 -1
  34. package/dist/esm/model/nodes/IfNode.js +5 -0
  35. package/dist/esm/model/nodes/LoopControllerNode.js +1 -1
  36. package/dist/esm/model/nodes/LoopUntilNode.js +214 -0
  37. package/dist/esm/model/nodes/ObjectNode.js +1 -1
  38. package/dist/esm/model/nodes/PromptNode.js +29 -6
  39. package/dist/esm/model/nodes/RaceInputsNode.js +1 -2
  40. package/dist/esm/model/nodes/ReadAllFilesNode.js +210 -0
  41. package/dist/esm/model/nodes/ReadDirectoryNode.js +31 -25
  42. package/dist/esm/model/nodes/ReferencedGraphAliasNode.js +199 -0
  43. package/dist/esm/model/nodes/ReplaceDatasetNode.js +1 -1
  44. package/dist/esm/model/nodes/SliceNode.js +0 -1
  45. package/dist/esm/model/nodes/SplitNode.js +1 -1
  46. package/dist/esm/model/nodes/SubGraphNode.js +0 -1
  47. package/dist/esm/model/nodes/TextNode.js +9 -4
  48. package/dist/esm/model/nodes/ToMarkdownTableNode.js +119 -0
  49. package/dist/esm/model/nodes/ToTreeNode.js +133 -0
  50. package/dist/esm/model/nodes/{GptFunctionNode.js → ToolNode.js} +10 -10
  51. package/dist/esm/model/nodes/UserInputNode.js +10 -12
  52. package/dist/esm/model/nodes/WriteFileNode.js +147 -0
  53. package/dist/esm/native/BrowserNativeApi.js +16 -1
  54. package/dist/esm/plugins/aidon/nodes/ChatAidonNode.js +5 -5
  55. package/dist/esm/plugins/anthropic/anthropic.js +29 -14
  56. package/dist/esm/plugins/anthropic/fetchEventSource.js +3 -2
  57. package/dist/esm/plugins/anthropic/nodes/ChatAnthropicNode.js +264 -147
  58. package/dist/esm/plugins/anthropic/plugin.js +9 -1
  59. package/dist/esm/plugins/assemblyAi/LemurQaNode.js +1 -1
  60. package/dist/esm/plugins/assemblyAi/LemurSummaryNode.js +1 -1
  61. package/dist/esm/plugins/gentrace/plugin.js +6 -6
  62. package/dist/esm/plugins/google/google.js +120 -6
  63. package/dist/esm/plugins/google/nodes/ChatGoogleNode.js +219 -56
  64. package/dist/esm/plugins/google/plugin.js +13 -6
  65. package/dist/esm/plugins/openai/nodes/RunThreadNode.js +2 -2
  66. package/dist/esm/plugins/openai/nodes/ThreadMessageNode.js +1 -1
  67. package/dist/esm/recording/ExecutionRecorder.js +59 -4
  68. package/dist/esm/utils/base64.js +13 -0
  69. package/dist/esm/utils/chatMessageToOpenAIChatCompletionMessage.js +15 -2
  70. package/dist/esm/utils/coerceType.js +4 -1
  71. package/dist/esm/utils/fetchEventSource.js +1 -1
  72. package/dist/esm/utils/interpolation.js +108 -3
  73. package/dist/esm/utils/openai.js +106 -50
  74. package/dist/esm/utils/paths.js +80 -0
  75. package/dist/esm/utils/serialization/serialization_v4.js +5 -0
  76. package/dist/types/api/createProcessor.d.ts +11 -5
  77. package/dist/types/api/looseDataValue.d.ts +4 -0
  78. package/dist/types/api/streaming.d.ts +1 -1
  79. package/dist/types/exports.d.ts +2 -0
  80. package/dist/types/integrations/CodeRunner.d.ts +18 -0
  81. package/dist/types/integrations/DatasetProvider.d.ts +1 -1
  82. package/dist/types/model/DataValue.d.ts +29 -6
  83. package/dist/types/model/EditorDefinition.d.ts +6 -1
  84. package/dist/types/model/GraphProcessor.d.ts +14 -7
  85. package/dist/types/model/NodeBase.d.ts +4 -0
  86. package/dist/types/model/NodeImpl.d.ts +5 -4
  87. package/dist/types/model/Nodes.d.ts +13 -4
  88. package/dist/types/model/ProcessContext.d.ts +16 -1
  89. package/dist/types/model/Project.d.ts +19 -7
  90. package/dist/types/model/ProjectReferenceLoader.d.ts +5 -0
  91. package/dist/types/model/RivetPlugin.d.ts +6 -0
  92. package/dist/types/model/RivetUIContext.d.ts +5 -1
  93. package/dist/types/model/Settings.d.ts +1 -0
  94. package/dist/types/model/nodes/AssemblePromptNode.d.ts +4 -1
  95. package/dist/types/model/nodes/ChatLoopNode.d.ts +21 -0
  96. package/dist/types/model/nodes/ChatNode.d.ts +2 -62
  97. package/dist/types/model/nodes/ChatNodeBase.d.ts +85 -0
  98. package/dist/types/model/nodes/CodeNode.d.ts +8 -2
  99. package/dist/types/model/nodes/CronNode.d.ts +34 -0
  100. package/dist/types/model/nodes/DelegateFunctionCallNode.d.ts +1 -0
  101. package/dist/types/model/nodes/DocumentNode.d.ts +28 -0
  102. package/dist/types/model/nodes/GetAllDatasetsNode.d.ts +2 -2
  103. package/dist/types/model/nodes/LoopUntilNode.d.ts +32 -0
  104. package/dist/types/model/nodes/ObjectNode.d.ts +2 -2
  105. package/dist/types/model/nodes/PromptNode.d.ts +2 -0
  106. package/dist/types/model/nodes/RaceInputsNode.d.ts +1 -2
  107. package/dist/types/model/nodes/ReadAllFilesNode.d.ts +30 -0
  108. package/dist/types/model/nodes/ReadDirectoryNode.d.ts +1 -1
  109. package/dist/types/model/nodes/ReferencedGraphAliasNode.d.ts +31 -0
  110. package/dist/types/model/nodes/SplitNode.d.ts +2 -2
  111. package/dist/types/model/nodes/ToMarkdownTableNode.d.ts +19 -0
  112. package/dist/types/model/nodes/ToTreeNode.d.ts +21 -0
  113. package/dist/types/model/nodes/UserInputNode.d.ts +2 -3
  114. package/dist/types/model/nodes/WriteFileNode.d.ts +23 -0
  115. package/dist/types/native/BrowserNativeApi.d.ts +8 -5
  116. package/dist/types/native/NativeApi.d.ts +12 -1
  117. package/dist/types/plugins/anthropic/anthropic.d.ts +94 -13
  118. package/dist/types/plugins/anthropic/nodes/ChatAnthropicNode.d.ts +7 -2
  119. package/dist/types/plugins/google/google.d.ts +101 -18
  120. package/dist/types/plugins/google/nodes/ChatGoogleNode.d.ts +3 -2
  121. package/dist/types/recording/RecordedEvents.d.ts +3 -0
  122. package/dist/types/utils/base64.d.ts +2 -1
  123. package/dist/types/utils/chatMessageToOpenAIChatCompletionMessage.d.ts +3 -1
  124. package/dist/types/utils/interpolation.d.ts +3 -0
  125. package/dist/types/utils/openai.d.ts +127 -21
  126. package/dist/types/utils/paths.d.ts +8 -0
  127. package/dist/types/utils/serialization/serialization_v3.d.ts +1 -0
  128. package/package.json +15 -11
  129. /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');
@@ -3,7 +3,7 @@ import { nanoid } from 'nanoid/non-secure';
3
3
  import { dedent } from 'ts-dedent';
4
4
  import { nodeDefinition } from '../NodeDefinition.js';
5
5
  import { getInputOrData, coerceType, newId, inferType } from '../../utils/index.js';
6
- import { arrayizeDataValue, unwrapDataValue } from '../DataValue.js';
6
+ import { unwrapDataValue } from '../DataValue.js';
7
7
  export class ReplaceDatasetNodeImpl extends NodeImpl {
8
8
  static create() {
9
9
  return {
@@ -3,7 +3,6 @@ import { nanoid } from 'nanoid/non-secure';
3
3
  import { NodeImpl } from '../NodeImpl.js';
4
4
  import { nodeDefinition } from '../NodeDefinition.js';
5
5
  import {} from '../GraphProcessor.js';
6
- import { entries } from '../../utils/typeSafety.js';
7
6
  import { dedent } from 'ts-dedent';
8
7
  import {} from '../EditorDefinition.js';
9
8
  import {} from '../../index.js';
@@ -85,7 +85,7 @@ export class SplitNodeImpl extends NodeImpl {
85
85
  }
86
86
  return normalized;
87
87
  }
88
- async process(inputs, context) {
88
+ async process(inputs) {
89
89
  const delimiter = getInputOrData(this.data, inputs, 'delimiter');
90
90
  const normalizedDelimiter = this.data.regex ? new RegExp(delimiter) : handleEscapeCharacters(delimiter);
91
91
  const stringToSplit = coerceType(inputs['string'], 'string');
@@ -12,7 +12,6 @@ import {} from '../ProcessContext.js';
12
12
  import {} from '../../index.js';
13
13
  import { dedent } from 'ts-dedent';
14
14
  import { getError } from '../../utils/errors.js';
15
- import { match } from 'ts-pattern';
16
15
  export class SubGraphNodeImpl extends NodeImpl {
17
16
  static create() {
18
17
  const chartNode = {
@@ -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');