@langchain/core 0.3.5-rc.0 → 0.3.6-rc.0

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.
@@ -126,24 +126,10 @@ class Graph {
126
126
  return edge;
127
127
  }
128
128
  firstNode() {
129
- const targets = new Set(this.edges.map((edge) => edge.target));
130
- const found = [];
131
- Object.values(this.nodes).forEach((node) => {
132
- if (!targets.has(node.id)) {
133
- found.push(node);
134
- }
135
- });
136
- return found[0];
129
+ return _firstNode(this);
137
130
  }
138
131
  lastNode() {
139
- const sources = new Set(this.edges.map((edge) => edge.source));
140
- const found = [];
141
- Object.values(this.nodes).forEach((node) => {
142
- if (!sources.has(node.id)) {
143
- found.push(node);
144
- }
145
- });
146
- return found[0];
132
+ return _lastNode(this);
147
133
  }
148
134
  /**
149
135
  * Add all nodes and edges from another graph.
@@ -179,20 +165,14 @@ class Graph {
179
165
  }
180
166
  trimFirstNode() {
181
167
  const firstNode = this.firstNode();
182
- if (firstNode) {
183
- const outgoingEdges = this.edges.filter((edge) => edge.source === firstNode.id);
184
- if (Object.keys(this.nodes).length === 1 || outgoingEdges.length === 1) {
185
- this.removeNode(firstNode);
186
- }
168
+ if (firstNode && _firstNode(this, [firstNode.id])) {
169
+ this.removeNode(firstNode);
187
170
  }
188
171
  }
189
172
  trimLastNode() {
190
173
  const lastNode = this.lastNode();
191
- if (lastNode) {
192
- const incomingEdges = this.edges.filter((edge) => edge.target === lastNode.id);
193
- if (Object.keys(this.nodes).length === 1 || incomingEdges.length === 1) {
194
- this.removeNode(lastNode);
195
- }
174
+ if (lastNode && _lastNode(this, [lastNode.id])) {
175
+ this.removeNode(lastNode);
196
176
  }
197
177
  }
198
178
  /**
@@ -252,3 +232,39 @@ class Graph {
252
232
  }
253
233
  }
254
234
  exports.Graph = Graph;
235
+ /**
236
+ * Find the single node that is not a target of any edge.
237
+ * Exclude nodes/sources with ids in the exclude list.
238
+ * If there is no such node, or there are multiple, return undefined.
239
+ * When drawing the graph, this node would be the origin.
240
+ */
241
+ function _firstNode(graph, exclude = []) {
242
+ const targets = new Set(graph.edges
243
+ .filter((edge) => !exclude.includes(edge.source))
244
+ .map((edge) => edge.target));
245
+ const found = [];
246
+ for (const node of Object.values(graph.nodes)) {
247
+ if (!exclude.includes(node.id) && !targets.has(node.id)) {
248
+ found.push(node);
249
+ }
250
+ }
251
+ return found.length === 1 ? found[0] : undefined;
252
+ }
253
+ /**
254
+ * Find the single node that is not a source of any edge.
255
+ * Exclude nodes/targets with ids in the exclude list.
256
+ * If there is no such node, or there are multiple, return undefined.
257
+ * When drawing the graph, this node would be the destination.
258
+ */
259
+ function _lastNode(graph, exclude = []) {
260
+ const sources = new Set(graph.edges
261
+ .filter((edge) => !exclude.includes(edge.target))
262
+ .map((edge) => edge.source));
263
+ const found = [];
264
+ for (const node of Object.values(graph.nodes)) {
265
+ if (!exclude.includes(node.id) && !sources.has(node.id)) {
266
+ found.push(node);
267
+ }
268
+ }
269
+ return found.length === 1 ? found[0] : undefined;
270
+ }
@@ -123,24 +123,10 @@ export class Graph {
123
123
  return edge;
124
124
  }
125
125
  firstNode() {
126
- const targets = new Set(this.edges.map((edge) => edge.target));
127
- const found = [];
128
- Object.values(this.nodes).forEach((node) => {
129
- if (!targets.has(node.id)) {
130
- found.push(node);
131
- }
132
- });
133
- return found[0];
126
+ return _firstNode(this);
134
127
  }
135
128
  lastNode() {
136
- const sources = new Set(this.edges.map((edge) => edge.source));
137
- const found = [];
138
- Object.values(this.nodes).forEach((node) => {
139
- if (!sources.has(node.id)) {
140
- found.push(node);
141
- }
142
- });
143
- return found[0];
129
+ return _lastNode(this);
144
130
  }
145
131
  /**
146
132
  * Add all nodes and edges from another graph.
@@ -176,20 +162,14 @@ export class Graph {
176
162
  }
177
163
  trimFirstNode() {
178
164
  const firstNode = this.firstNode();
179
- if (firstNode) {
180
- const outgoingEdges = this.edges.filter((edge) => edge.source === firstNode.id);
181
- if (Object.keys(this.nodes).length === 1 || outgoingEdges.length === 1) {
182
- this.removeNode(firstNode);
183
- }
165
+ if (firstNode && _firstNode(this, [firstNode.id])) {
166
+ this.removeNode(firstNode);
184
167
  }
185
168
  }
186
169
  trimLastNode() {
187
170
  const lastNode = this.lastNode();
188
- if (lastNode) {
189
- const incomingEdges = this.edges.filter((edge) => edge.target === lastNode.id);
190
- if (Object.keys(this.nodes).length === 1 || incomingEdges.length === 1) {
191
- this.removeNode(lastNode);
192
- }
171
+ if (lastNode && _lastNode(this, [lastNode.id])) {
172
+ this.removeNode(lastNode);
193
173
  }
194
174
  }
195
175
  /**
@@ -248,3 +228,39 @@ export class Graph {
248
228
  });
249
229
  }
250
230
  }
231
+ /**
232
+ * Find the single node that is not a target of any edge.
233
+ * Exclude nodes/sources with ids in the exclude list.
234
+ * If there is no such node, or there are multiple, return undefined.
235
+ * When drawing the graph, this node would be the origin.
236
+ */
237
+ function _firstNode(graph, exclude = []) {
238
+ const targets = new Set(graph.edges
239
+ .filter((edge) => !exclude.includes(edge.source))
240
+ .map((edge) => edge.target));
241
+ const found = [];
242
+ for (const node of Object.values(graph.nodes)) {
243
+ if (!exclude.includes(node.id) && !targets.has(node.id)) {
244
+ found.push(node);
245
+ }
246
+ }
247
+ return found.length === 1 ? found[0] : undefined;
248
+ }
249
+ /**
250
+ * Find the single node that is not a source of any edge.
251
+ * Exclude nodes/targets with ids in the exclude list.
252
+ * If there is no such node, or there are multiple, return undefined.
253
+ * When drawing the graph, this node would be the destination.
254
+ */
255
+ function _lastNode(graph, exclude = []) {
256
+ const sources = new Set(graph.edges
257
+ .filter((edge) => !exclude.includes(edge.target))
258
+ .map((edge) => edge.source));
259
+ const found = [];
260
+ for (const node of Object.values(graph.nodes)) {
261
+ if (!exclude.includes(node.id) && !sources.has(node.id)) {
262
+ found.push(node);
263
+ }
264
+ }
265
+ return found.length === 1 ? found[0] : undefined;
266
+ }
@@ -41,8 +41,8 @@ function drawMermaid(nodes, edges, config) {
41
41
  ? `<p>${nodeName}</p>`
42
42
  : nodeName;
43
43
  let finalLabel = label;
44
- if (node.metadata) {
45
- finalLabel += `<hr/><small><em>${Object.entries(node.metadata)
44
+ if (Object.keys(node.metadata ?? {}).length) {
45
+ finalLabel += `<hr/><small><em>${Object.entries(node.metadata ?? {})
46
46
  .map(([k, v]) => `${k} = ${v}`)
47
47
  .join("\n")}</em></small>`;
48
48
  }
@@ -82,7 +82,7 @@ function drawMermaid(nodes, edges, config) {
82
82
  const { source, target, data, conditional } = edge;
83
83
  let edgeLabel = "";
84
84
  if (data !== undefined) {
85
- let edgeData = String(data);
85
+ let edgeData = data;
86
86
  const words = edgeData.split(" ");
87
87
  if (words.length > wrapLabelNWords) {
88
88
  edgeData = Array.from({ length: Math.ceil(words.length / wrapLabelNWords) }, (_, i) => words
@@ -38,8 +38,8 @@ export function drawMermaid(nodes, edges, config) {
38
38
  ? `<p>${nodeName}</p>`
39
39
  : nodeName;
40
40
  let finalLabel = label;
41
- if (node.metadata) {
42
- finalLabel += `<hr/><small><em>${Object.entries(node.metadata)
41
+ if (Object.keys(node.metadata ?? {}).length) {
42
+ finalLabel += `<hr/><small><em>${Object.entries(node.metadata ?? {})
43
43
  .map(([k, v]) => `${k} = ${v}`)
44
44
  .join("\n")}</em></small>`;
45
45
  }
@@ -79,7 +79,7 @@ export function drawMermaid(nodes, edges, config) {
79
79
  const { source, target, data, conditional } = edge;
80
80
  let edgeLabel = "";
81
81
  if (data !== undefined) {
82
- let edgeData = String(data);
82
+ let edgeData = data;
83
83
  const words = edgeData.split(" ");
84
84
  if (words.length > wrapLabelNWords) {
85
85
  edgeData = Array.from({ length: Math.ceil(words.length / wrapLabelNWords) }, (_, i) => words
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/core",
3
- "version": "0.3.5-rc.0",
3
+ "version": "0.3.6-rc.0",
4
4
  "description": "Core LangChain.js abstractions and schemas",
5
5
  "type": "module",
6
6
  "engines": {