@langgraph-js/pure-graph 3.2.4 → 3.3.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.
Files changed (33) hide show
  1. package/dist/adapter/fetch/index.js +4 -3
  2. package/dist/adapter/fetch/index.js.map +1 -1
  3. package/dist/adapter/nextjs/index.js +1 -1
  4. package/dist/adapter/zod.d.ts +1 -0
  5. package/dist/{createEndpoint-BDHfY6AZ.js → createEndpoint-D27R5Yhn.js} +53 -11
  6. package/dist/createEndpoint-D27R5Yhn.js.map +1 -0
  7. package/dist/createEndpoint.d.ts +2 -1
  8. package/dist/global.d.ts +15 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.js +2 -2
  11. package/dist/{queue-CPJTzcgl.js → queue-CS3K-zd_.js} +2 -2
  12. package/dist/{queue-CPJTzcgl.js.map → queue-CS3K-zd_.js.map} +1 -1
  13. package/dist/remote/index.js +1 -1
  14. package/dist/{remote-threads-CrG03ZS7.js → remote-threads-UpSB8X-e.js} +19 -1
  15. package/dist/remote-threads-UpSB8X-e.js.map +1 -0
  16. package/dist/{sqlite-adapter-CJXgit1j.js → sqlite-adapter-D5g0LbUq.js} +15 -2
  17. package/dist/sqlite-adapter-D5g0LbUq.js.map +1 -0
  18. package/dist/storage/kysely/remote-threads.d.ts +4 -0
  19. package/dist/storage/kysely/sqlite-adapter.d.ts +5 -0
  20. package/dist/storage/kysely/threads.d.ts +3 -2
  21. package/dist/storage/kysely/types.d.ts +1 -0
  22. package/dist/storage/memory/threads.d.ts +4 -3
  23. package/dist/{stream-8w3eP9hU.js → stream-Bleed1lp.js} +104 -14
  24. package/dist/stream-Bleed1lp.js.map +1 -0
  25. package/dist/threads/index.d.ts +9 -3
  26. package/dist/types.d.ts +10 -2
  27. package/dist/utils/titleGenerator.d.ts +20 -0
  28. package/dist/utils/titleGeneratorHelper.d.ts +17 -0
  29. package/package.json +1 -1
  30. package/dist/createEndpoint-BDHfY6AZ.js.map +0 -1
  31. package/dist/remote-threads-CrG03ZS7.js.map +0 -1
  32. package/dist/sqlite-adapter-CJXgit1j.js.map +0 -1
  33. package/dist/stream-8w3eP9hU.js.map +0 -1
@@ -486,7 +486,8 @@ class KyselyThreadsManager {
486
486
  metadata: this.adapter.dbToJson(existing.metadata),
487
487
  status: existing.status,
488
488
  values: existing.values ? this.adapter.dbToJson(existing.values) : null,
489
- interrupts: this.adapter.dbToJson(existing.interrupts)
489
+ interrupts: this.adapter.dbToJson(existing.interrupts),
490
+ title: existing.title
490
491
  };
491
492
  }
492
493
  }
@@ -507,7 +508,8 @@ class KyselyThreadsManager {
507
508
  metadata,
508
509
  status: "idle",
509
510
  values: null,
510
- interrupts
511
+ interrupts,
512
+ title: null
511
513
  };
512
514
  }
513
515
  async search(query) {
@@ -516,7 +518,7 @@ class KyselyThreadsManager {
516
518
  if (query?.select) {
517
519
  selectedFields = new Set(query.select);
518
520
  } else if (query?.withoutDetails) {
519
- selectedFields = /* @__PURE__ */ new Set(["thread_id", "created_at", "updated_at", "metadata", "status"]);
521
+ selectedFields = /* @__PURE__ */ new Set(["thread_id", "created_at", "updated_at", "metadata", "status", "title"]);
520
522
  } else {
521
523
  selectedFields = /* @__PURE__ */ new Set([
522
524
  "thread_id",
@@ -525,7 +527,8 @@ class KyselyThreadsManager {
525
527
  "metadata",
526
528
  "status",
527
529
  "values",
528
- "interrupts"
530
+ "interrupts",
531
+ "title"
529
532
  ]);
530
533
  }
531
534
  const selections = [];
@@ -536,6 +539,7 @@ class KyselyThreadsManager {
536
539
  if (selectedFields.has("status")) selections.push("status");
537
540
  if (selectedFields.has("values")) selections.push("values");
538
541
  if (selectedFields.has("interrupts")) selections.push("interrupts");
542
+ if (selectedFields.has("title")) selections.push("title");
539
543
  if (selections.length > 0) {
540
544
  queryBuilder = queryBuilder.select(selections);
541
545
  } else {
@@ -579,6 +583,7 @@ class KyselyThreadsManager {
579
583
  if (selectedFields.has("values"))
580
584
  result.values = row.values ? this.adapter.dbToJson(row.values) : null;
581
585
  if (selectedFields.has("interrupts")) result.interrupts = this.adapter.dbToJson(row.interrupts);
586
+ if (selectedFields.has("title")) result.title = row.title;
582
587
  return result;
583
588
  });
584
589
  }
@@ -595,7 +600,8 @@ class KyselyThreadsManager {
595
600
  metadata: this.adapter.dbToJson(row.metadata),
596
601
  status: row.status,
597
602
  values: row.values ? this.adapter.dbToJson(row.values) : null,
598
- interrupts: this.adapter.dbToJson(row.interrupts)
603
+ interrupts: this.adapter.dbToJson(row.interrupts),
604
+ title: row.title
599
605
  };
600
606
  }
601
607
  async set(threadId, thread) {
@@ -618,6 +624,9 @@ class KyselyThreadsManager {
618
624
  if (thread.interrupts !== void 0) {
619
625
  updates.interrupts = this.adapter.jsonToDb(thread.interrupts);
620
626
  }
627
+ if (thread.title !== void 0) {
628
+ updates.title = thread.title;
629
+ }
621
630
  await this.db.updateTable("threads").set(updates).where("thread_id", "=", threadId).execute();
622
631
  }
623
632
  async delete(threadId) {
@@ -747,6 +756,9 @@ class KyselyThreadsManager {
747
756
  if (updates.interrupts !== void 0) {
748
757
  patchUpdates.interrupts = this.adapter.jsonToDb(updates.interrupts);
749
758
  }
759
+ if (updates.title !== void 0) {
760
+ patchUpdates.title = updates.title;
761
+ }
750
762
  await this.db.updateTable("threads").set(patchUpdates).where("thread_id", "=", threadId).execute();
751
763
  return await this.get(threadId);
752
764
  }
@@ -828,7 +840,8 @@ class KyselyThreadsManager {
828
840
  metadata: this.adapter.jsonToDb(originalThread.metadata),
829
841
  status: originalThread.status,
830
842
  values: originalThread.values ? this.adapter.jsonToDb(originalThread.values) : null,
831
- interrupts: this.adapter.jsonToDb(originalThread.interrupts)
843
+ interrupts: this.adapter.jsonToDb(originalThread.interrupts),
844
+ title: originalThread.title
832
845
  }).execute();
833
846
  const checkpoints = await this.db.selectFrom("checkpoints").selectAll().where("thread_id", "=", threadId).orderBy("created_at", "asc").execute();
834
847
  for (const cp of checkpoints) {
@@ -861,6 +874,13 @@ class KyselyThreadsManager {
861
874
  metadata: this.adapter.jsonToDb(metadata || {})
862
875
  }).execute();
863
876
  }
877
+ async setTitleIfNull(threadId, title) {
878
+ const result = await this.db.updateTable("threads").set({
879
+ title,
880
+ updated_at: this.adapter.dateToDb(/* @__PURE__ */ new Date())
881
+ }).where("thread_id", "=", threadId).where("title", "is", null).executeTakeFirst();
882
+ return result.numUpdatedRows > 0n;
883
+ }
864
884
  }
865
885
 
866
886
  function _parseShallowKey(key) {
@@ -1194,7 +1214,6 @@ class MemoryStreamQueue extends BaseStreamQueue {
1194
1214
  if (this.isDestroyed) return;
1195
1215
  const data = this.compressMessages ? await this.encodeData(item) : item;
1196
1216
  process.env.LG_TEMP_MESSAGE !== "true" && this.data.push(data);
1197
- console.log(process.env.LG_TEMP_MESSAGE !== "true");
1198
1217
  this.emit("dataChange", data);
1199
1218
  }
1200
1219
  onDataChange(listener) {
@@ -1367,7 +1386,8 @@ class MemoryThreadsManager {
1367
1386
  metadata: payload?.metadata || {},
1368
1387
  status: "idle",
1369
1388
  values: null,
1370
- interrupts: {}
1389
+ interrupts: {},
1390
+ title: null
1371
1391
  };
1372
1392
  this.checkpoints.set(threadId, []);
1373
1393
  this.threads.push(thread);
@@ -1445,7 +1465,8 @@ class MemoryThreadsManager {
1445
1465
  "metadata",
1446
1466
  "status",
1447
1467
  "values",
1448
- "interrupts"
1468
+ "interrupts",
1469
+ "title"
1449
1470
  ]);
1450
1471
  }
1451
1472
  if (includeFields.has("thread_id")) result.thread_id = i.thread_id;
@@ -1455,6 +1476,7 @@ class MemoryThreadsManager {
1455
1476
  if (includeFields.has("status")) result.status = i.status;
1456
1477
  if (includeFields.has("values")) result.values = i.values;
1457
1478
  if (includeFields.has("interrupts")) result.interrupts = i.interrupts;
1479
+ if (includeFields.has("title")) result.title = i.title;
1458
1480
  return result;
1459
1481
  });
1460
1482
  }
@@ -1685,6 +1707,21 @@ class MemoryThreadsManager {
1685
1707
  checkpoints.push(checkpoint);
1686
1708
  this.checkpoints.set(threadId, checkpoints);
1687
1709
  }
1710
+ async setTitleIfNull(threadId, title) {
1711
+ const index = this.threads.findIndex((t) => t.thread_id === threadId);
1712
+ if (index === -1) {
1713
+ throw new Error(`Thread with ID ${threadId} not found.`);
1714
+ }
1715
+ if (this.threads[index].title === null) {
1716
+ this.threads[index] = {
1717
+ ...this.threads[index],
1718
+ title,
1719
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1720
+ };
1721
+ return true;
1722
+ }
1723
+ return false;
1724
+ }
1688
1725
  }
1689
1726
 
1690
1727
  const createCheckPointer = async () => {
@@ -1736,7 +1773,7 @@ const createMessageQueue = async () => {
1736
1773
  let q;
1737
1774
  if (process.env.REDIS_URL) {
1738
1775
  console.debug("LG | Using redis as stream queue");
1739
- const { RedisStreamQueue } = await import('./queue-CPJTzcgl.js');
1776
+ const { RedisStreamQueue } = await import('./queue-CS3K-zd_.js');
1740
1777
  q = RedisStreamQueue;
1741
1778
  } else {
1742
1779
  q = MemoryStreamQueue;
@@ -1755,7 +1792,7 @@ const createThreadManager = async (config) => {
1755
1792
  const dbType = getDatabaseType(process.env.DATABASE_URL);
1756
1793
  if (dbType === "remote") {
1757
1794
  console.debug("LG | Using Remote PostgreSQL ThreadsManager");
1758
- const { RemoteKyselyThreadsManager } = await import('./remote-threads-CrG03ZS7.js');
1795
+ const { RemoteKyselyThreadsManager } = await import('./remote-threads-UpSB8X-e.js');
1759
1796
  const threadsManager = new RemoteKyselyThreadsManager(process.env.DATABASE_URL);
1760
1797
  if (process.env.DATABASE_INIT === "true") {
1761
1798
  await threadsManager.setup();
@@ -1776,7 +1813,7 @@ const createThreadManager = async (config) => {
1776
1813
  }
1777
1814
  if (process.env.SQLITE_DATABASE_URI && config.checkpointer) {
1778
1815
  console.debug("LG | Using SQLite ThreadsManager");
1779
- const { SQLiteAdapter } = await import('./sqlite-adapter-CJXgit1j.js');
1816
+ const { SQLiteAdapter } = await import('./sqlite-adapter-D5g0LbUq.js');
1780
1817
  const database = config.checkpointer.db;
1781
1818
  const threadsManager = new KyselyThreadsManager(new SQLiteAdapter(database));
1782
1819
  await threadsManager.setup();
@@ -1785,11 +1822,64 @@ const createThreadManager = async (config) => {
1785
1822
  return new MemoryThreadsManager();
1786
1823
  };
1787
1824
 
1825
+ function extractTextContent(content) {
1826
+ if (typeof content === "string") {
1827
+ return content;
1828
+ }
1829
+ if (Array.isArray(content)) {
1830
+ const textPart = content.find((part) => part.type === "text");
1831
+ return textPart?.text || "";
1832
+ }
1833
+ if (content?.text) {
1834
+ return content.text;
1835
+ }
1836
+ return "";
1837
+ }
1838
+ const defaultTitleGenerator = (state, context) => {
1839
+ const messages = state?.messages;
1840
+ if (!messages || !Array.isArray(messages) || messages.length === 0) {
1841
+ return null;
1842
+ }
1843
+ const firstMessage = messages[0];
1844
+ if (!firstMessage) {
1845
+ return null;
1846
+ }
1847
+ const content = extractTextContent(firstMessage.content);
1848
+ if (!content) {
1849
+ return null;
1850
+ }
1851
+ const cleanedContent = content.trim().replace(/\n/g, " ");
1852
+ if (!cleanedContent) {
1853
+ return null;
1854
+ }
1855
+ const maxLength = 15;
1856
+ const title = cleanedContent.slice(0, maxLength);
1857
+ return title.length < cleanedContent.length ? `${title}...` : title;
1858
+ };
1859
+
1788
1860
  class LangGraphGlobal {
1789
1861
  static globalMessageQueue = null;
1790
1862
  static globalCheckPointer = null;
1791
1863
  static globalThreadsManager = null;
1792
1864
  static isInitialized = null;
1865
+ /**
1866
+ * 全局标题生成器
1867
+ * 可通过 setTitleGenerator 替换
1868
+ */
1869
+ static _titleGenerator = defaultTitleGenerator;
1870
+ /**
1871
+ * 设置自定义标题生成器
1872
+ * @param generator 标题生成函数,传入 null 可禁用标题生成
1873
+ */
1874
+ static setTitleGenerator(generator) {
1875
+ LangGraphGlobal._titleGenerator = generator;
1876
+ }
1877
+ /**
1878
+ * 获取当前标题生成器
1879
+ */
1880
+ static getTitleGenerator() {
1881
+ return LangGraphGlobal._titleGenerator;
1882
+ }
1793
1883
  static async initGlobal() {
1794
1884
  if (LangGraphGlobal.isInitialized) {
1795
1885
  return LangGraphGlobal.isInitialized;
@@ -2018,5 +2108,5 @@ async function* streamState(threads, run, payload, options) {
2018
2108
  }
2019
2109
  }
2020
2110
 
2021
- export { BaseStreamQueue as B, CancelEventMessage as C, GRAPHS as G, KyselyThreadsManager as K, LangGraphGlobal as L, streamState as a, getGraph as g, registerGraph as r, serialiseAsDict as s };
2022
- //# sourceMappingURL=stream-8w3eP9hU.js.map
2111
+ export { BaseStreamQueue as B, CancelEventMessage as C, GRAPHS as G, KyselyThreadsManager as K, LangGraphGlobal as L, streamState as a, defaultTitleGenerator as d, getGraph as g, registerGraph as r, serialiseAsDict as s };
2112
+ //# sourceMappingURL=stream-Bleed1lp.js.map