@langgraph-js/pure-graph 3.2.0 → 3.2.2
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/dist/adapter/fetch/index.js +128 -30
- package/dist/adapter/fetch/index.js.map +1 -1
- package/dist/adapter/fetch/utils.d.ts +13 -3
- package/dist/adapter/nextjs/index.js +1 -1
- package/dist/{checkpoint-C5AFBYE-.js → checkpoint-CY59Lr2q.js} +3 -3
- package/dist/checkpoint-CY59Lr2q.js.map +1 -0
- package/dist/{createEndpoint-C2KsYHDx.js → createEndpoint-vMmFiMSz.js} +20 -5
- package/dist/createEndpoint-vMmFiMSz.js.map +1 -0
- package/dist/createEndpoint.d.ts +2 -1
- package/dist/index.js +2 -2
- package/dist/queue/stream_queue.d.ts +3 -1
- package/dist/{queue-DySatFkr.js → queue-CUe5TDP1.js} +120 -16
- package/dist/queue-CUe5TDP1.js.map +1 -0
- package/dist/remote/index.js +1 -1
- package/dist/{shallow-checkpoint-BEhTdp7z.js → shallow-checkpoint-ImbLxYNR.js} +4 -4
- package/dist/shallow-checkpoint-ImbLxYNR.js.map +1 -0
- package/dist/{sqlite-adapter-oBA95xba.js → sqlite-adapter-CJXgit1j.js} +7 -12
- package/dist/sqlite-adapter-CJXgit1j.js.map +1 -0
- package/dist/storage/memory/queue.d.ts +6 -0
- package/dist/storage/redis/queue.d.ts +14 -1
- package/dist/{stream-pZfO6Y-p.js → stream-jYlUzTZO.js} +190 -62
- package/dist/stream-jYlUzTZO.js.map +1 -0
- package/package.json +2 -1
- package/dist/checkpoint-C5AFBYE-.js.map +0 -1
- package/dist/createEndpoint-C2KsYHDx.js.map +0 -1
- package/dist/queue-DySatFkr.js.map +0 -1
- package/dist/shallow-checkpoint-BEhTdp7z.js.map +0 -1
- package/dist/sqlite-adapter-oBA95xba.js.map +0 -1
- package/dist/stream-pZfO6Y-p.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shallow-checkpoint-ImbLxYNR.js","sources":["../src/storage/sqlite/shallow-checkpoint.ts"],"sourcesContent":["import { Dialect, Kysely, sql } from 'kysely';\nimport type { RunnableConfig } from '@langchain/core/runnables';\n\nimport {\n BaseCheckpointSaver,\n type Checkpoint,\n type CheckpointListOptions,\n type CheckpointTuple,\n type SerializerProtocol,\n type PendingWrite,\n type CheckpointMetadata,\n TASKS,\n copyCheckpoint,\n maxChannelVersion,\n getCheckpointId,\n WRITES_IDX_MAP,\n uuid6,\n} from '@langchain/langgraph-checkpoint';\n\n/**\n * SQLite 重试配置\n */\nconst SQLITE_RETRY_CONFIG = {\n maxRetries: 3,\n baseDelayMs: 100,\n isRetryableError: (error: any): boolean => {\n const msg = error?.message?.toLowerCase() || '';\n // 精确匹配 SQLITE_BUSY 和 database is locked\n // 注意:不重试事务状态错误(如 cannot rollback),这些可能是结构性问题\n return (\n msg.includes('sqlite_busy') ||\n msg.includes('database is locked') ||\n msg.includes('database disk image is malformed') ||\n msg === 'sqlite_busy' ||\n msg === 'database is locked'\n );\n },\n};\n\n/**\n * 带重试的数据库操作包装器\n */\nasync function withRetry<T>(operation: () => Promise<T>, context?: string): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < SQLITE_RETRY_CONFIG.maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error: any) {\n lastError = error;\n\n if (!SQLITE_RETRY_CONFIG.isRetryableError(error)) {\n throw error;\n }\n\n if (attempt < SQLITE_RETRY_CONFIG.maxRetries - 1) {\n const delay = SQLITE_RETRY_CONFIG.baseDelayMs * Math.pow(2, attempt);\n console.warn(\n `SQLite lock detected${context ? ` (${context})` : ''}, retrying in ${delay}ms (attempt ${attempt + 1}/${SQLITE_RETRY_CONFIG.maxRetries})`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError;\n}\n\n/**\n * Helper function for deterministic object comparison\n * Used for deep metadata filtering\n */\nfunction deterministicStringify(obj: any): string {\n if (obj === null || typeof obj !== 'object') {\n return JSON.stringify(obj);\n }\n if (Array.isArray(obj)) {\n return JSON.stringify(obj.map((item) => deterministicStringify(item)));\n }\n const sortedObj: Record<string, any> = {};\n const sortedKeys = Object.keys(obj).sort();\n for (const key of sortedKeys) {\n sortedObj[key] = obj[key];\n }\n return JSON.stringify(sortedObj, (_, value) => {\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n const sorted: Record<string, any> = {};\n const keys = Object.keys(value).sort();\n for (const k of keys) {\n sorted[k] = value[k];\n }\n return sorted;\n }\n return value;\n });\n}\n\n// Kysely 数据库表类型定义 - 浅层模式\ninterface ShallowCheckpointsTable {\n thread_id: string;\n checkpoint_ns: string;\n checkpoint_id: string;\n parent_checkpoint_id: string | null;\n type: string | null;\n checkpoint: Uint8Array;\n metadata: Uint8Array;\n checkpoint_ts: number; // 时间戳用于排序\n}\n\ninterface WritesTable {\n thread_id: string;\n checkpoint_ns: string;\n checkpoint_id: string;\n task_id: string;\n idx: number;\n channel: string;\n type: string | null;\n value: Uint8Array | null;\n}\n\ninterface ShallowCheckpointDatabase {\n shallow_checkpoints: ShallowCheckpointsTable;\n writes: WritesTable;\n}\n\n// Valid metadata keys for filtering\nconst checkpointMetadataKeys = ['source', 'step', 'parents'] as const;\n\ntype CheckKeys<T, K extends readonly (keyof T)[]> = [K[number]] extends [keyof T]\n ? [keyof T] extends [K[number]]\n ? K\n : never\n : never;\n\nfunction validateKeys<T, K extends readonly (keyof T)[]>(keys: CheckKeys<T, K>): K {\n return keys;\n}\n\nconst validCheckpointMetadataKeys = validateKeys<CheckpointMetadata, typeof checkpointMetadataKeys>(\n checkpointMetadataKeys,\n);\n\n/**\n * SqliteShallowSaver - SQLite 浅层检查点存储器\n *\n * 特性:\n * - 每个 thread_id + checkpoint_ns 组合只保留最新的 checkpoint\n * - 新 checkpoint 写入时自动清理旧 checkpoint 的 writes\n * - 使用 checkpoint_ts 时间戳排序\n * - 大幅减少存储数据量\n */\nexport class SqliteShallowSaver extends BaseCheckpointSaver {\n db: Kysely<ShallowCheckpointDatabase>;\n protected isSetup: boolean;\n\n constructor(dialect: Dialect, serde?: SerializerProtocol) {\n super(serde);\n this.db = new Kysely<ShallowCheckpointDatabase>({\n dialect,\n });\n this.isSetup = false;\n }\n\n static async fromConnStringAsync(connStringOrLocalPath: string): Promise<SqliteShallowSaver> {\n let saver: SqliteShallowSaver;\n /** @ts-ignore */\n if (globalThis.Bun) {\n console.log('LG | Using BunSqliteDialect ' + connStringOrLocalPath);\n const { BunSqliteDialect } = await import('kysely-bun-worker/normal');\n // 使用 BunSqliteDialect(非 Worker 模式)避免 Worker 事务状态同步问题\n // BunWorkerDialect 在高并发下可能出现 \"cannot rollback - no transaction is active\"\n saver = new SqliteShallowSaver(new BunSqliteDialect({ url: connStringOrLocalPath }));\n } else {\n /** @ts-ignore */\n console.log('LG | Using NodeWasmDialect');\n const { default: SqliteDatabase } = await import('node-sqlite3-wasm');\n const { NodeWasmDialect } = await import('kysely-wasm');\n console.log(connStringOrLocalPath);\n const wasm = new NodeWasmDialect({\n database: new SqliteDatabase.Database(connStringOrLocalPath),\n });\n saver = new SqliteShallowSaver(wasm);\n }\n await saver.setup();\n return saver;\n }\n\n protected async setup(): Promise<void> {\n if (this.isSetup) {\n return;\n }\n\n // 锁等待超时 5 秒\n await sql`PRAGMA busy_timeout = 5000`.execute(this.db as any);\n\n // WAL 模式 - 允许读写并发\n await sql`PRAGMA journal_mode = WAL`.execute(this.db as any);\n\n // NORMAL 模式 - 平衡数据安全与性能\n await sql`PRAGMA synchronous = NORMAL`.execute(this.db as any);\n\n // WAL 自动检查点\n await sql`PRAGMA wal_autocheckpoint = 1000`.execute(this.db as any);\n\n // 创建浅层 checkpoints 表 - 使用复合主键 (thread_id, checkpoint_ns)\n await sql`\nCREATE TABLE IF NOT EXISTS shallow_checkpoints (\n thread_id TEXT NOT NULL,\n checkpoint_ns TEXT NOT NULL DEFAULT '',\n checkpoint_id TEXT NOT NULL,\n parent_checkpoint_id TEXT,\n type TEXT,\n checkpoint BLOB,\n metadata BLOB,\n checkpoint_ts INTEGER NOT NULL DEFAULT 0,\n PRIMARY KEY (thread_id, checkpoint_ns)\n)`.execute(this.db as any);\n\n // 创建 checkpoint_ts 索引用于排序\n await sql`\nCREATE INDEX IF NOT EXISTS idx_shallow_checkpoints_ts \nON shallow_checkpoints(checkpoint_ts DESC)`.execute(this.db as any);\n\n // 创建 writes 表\n await sql`\nCREATE TABLE IF NOT EXISTS writes (\n thread_id TEXT NOT NULL,\n checkpoint_ns TEXT NOT NULL DEFAULT '',\n checkpoint_id TEXT NOT NULL,\n task_id TEXT NOT NULL,\n idx INTEGER NOT NULL,\n channel TEXT NOT NULL,\n type TEXT,\n value BLOB,\n PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)\n)`.execute(this.db as any);\n\n this.isSetup = true;\n }\n\n /**\n * 获取 checkpoint(便捷方法)\n */\n async get(config: RunnableConfig): Promise<Checkpoint | undefined> {\n const tuple = await this.getTuple(config);\n return tuple?.checkpoint;\n }\n\n async getTuple(config: RunnableConfig): Promise<CheckpointTuple | undefined> {\n await this.setup();\n const threadId = config.configurable?.thread_id;\n const checkpointNs = config.configurable?.checkpoint_ns ?? '';\n const requestedCheckpointId = getCheckpointId(config);\n\n if (threadId === undefined) {\n return undefined;\n }\n\n let query = this.db\n .selectFrom('shallow_checkpoints')\n .select([\n 'thread_id',\n 'checkpoint_ns',\n 'checkpoint_id',\n 'parent_checkpoint_id',\n 'type',\n 'checkpoint',\n 'metadata',\n 'checkpoint_ts',\n sql<string>`(\n SELECT json_group_array(\n json_object(\n 'task_id', pw.task_id,\n 'channel', pw.channel,\n 'type', pw.type,\n 'value', CAST(pw.value AS TEXT)\n )\n )\n FROM writes as pw\n WHERE pw.thread_id = shallow_checkpoints.thread_id\n AND pw.checkpoint_ns = shallow_checkpoints.checkpoint_ns\n AND pw.checkpoint_id = shallow_checkpoints.checkpoint_id\n )`.as('pending_writes'),\n sql<string>`(\n SELECT json_group_array(\n json_object(\n 'type', ps.type,\n 'value', CAST(ps.value AS TEXT)\n )\n )\n FROM writes as ps\n WHERE ps.thread_id = shallow_checkpoints.thread_id\n AND ps.checkpoint_ns = shallow_checkpoints.checkpoint_ns\n AND ps.checkpoint_id = shallow_checkpoints.parent_checkpoint_id\n AND ps.channel = ${TASKS}\n ORDER BY ps.idx\n )`.as('pending_sends'),\n ])\n .where('thread_id', '=', threadId)\n .where('checkpoint_ns', '=', checkpointNs);\n\n // 如果指定了 checkpoint_id,需要验证是否匹配\n if (requestedCheckpointId) {\n query = query.where('checkpoint_id', '=', requestedCheckpointId);\n }\n\n const row = await query.executeTakeFirst();\n if (!row) return undefined;\n\n // 如果请求了特定的 checkpoint_id 但不匹配(在 shallow 模式下只有一条记录)\n if (requestedCheckpointId && row.checkpoint_id !== requestedCheckpointId) {\n return undefined;\n }\n\n // 反序列化 pending writes\n const pendingWrites = await Promise.all(\n (JSON.parse(row.pending_writes || '[]') as Array<{\n task_id: string;\n channel: string;\n type: string;\n value: string;\n }>).map(async (write) => {\n return [\n write.task_id,\n write.channel,\n await this.serde.loadsTyped(write.type ?? 'json', write.value ?? ''),\n ] as [string, string, unknown];\n }),\n );\n\n // 反序列化 checkpoint\n const checkpoint = (await this.serde.loadsTyped(\n row.type ?? 'json',\n new TextDecoder().decode(row.checkpoint),\n )) as Checkpoint;\n\n // 处理 v < 4 迁移\n if (checkpoint.v < 4 && row.parent_checkpoint_id != null) {\n await this.migratePendingSends(checkpoint, row.thread_id, row.parent_checkpoint_id);\n }\n\n const finalConfig: RunnableConfig = {\n configurable: {\n thread_id: row.thread_id,\n checkpoint_ns: row.checkpoint_ns,\n checkpoint_id: row.checkpoint_id,\n },\n };\n\n return {\n checkpoint,\n config: finalConfig,\n metadata: (await this.serde.loadsTyped(\n row.type ?? 'json',\n new TextDecoder().decode(row.metadata),\n )) as CheckpointMetadata,\n parentConfig: row.parent_checkpoint_id\n ? {\n configurable: {\n thread_id: row.thread_id,\n checkpoint_ns: row.checkpoint_ns,\n checkpoint_id: row.parent_checkpoint_id,\n },\n }\n : undefined,\n pendingWrites,\n };\n }\n\n async *list(config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple> {\n await this.setup();\n const { limit, before, filter } = options ?? {};\n const threadId = config.configurable?.thread_id;\n const checkpointNs = config.configurable?.checkpoint_ns;\n\n let query = this.db.selectFrom('shallow_checkpoints').select([\n 'thread_id',\n 'checkpoint_ns',\n 'checkpoint_id',\n 'parent_checkpoint_id',\n 'type',\n 'checkpoint',\n 'metadata',\n 'checkpoint_ts',\n sql<string>`(\n SELECT json_group_array(\n json_object(\n 'task_id', pw.task_id,\n 'channel', pw.channel,\n 'type', pw.type,\n 'value', CAST(pw.value AS TEXT)\n )\n )\n FROM writes as pw\n WHERE pw.thread_id = shallow_checkpoints.thread_id\n AND pw.checkpoint_ns = shallow_checkpoints.checkpoint_ns\n AND pw.checkpoint_id = shallow_checkpoints.checkpoint_id\n )`.as('pending_writes'),\n ]);\n\n if (threadId) {\n query = query.where('thread_id', '=', threadId);\n }\n\n if (checkpointNs !== undefined && checkpointNs !== null) {\n query = query.where('checkpoint_ns', '=', checkpointNs);\n }\n\n if (before?.configurable?.checkpoint_id !== undefined) {\n query = query.where('checkpoint_id', '<', before.configurable.checkpoint_id);\n }\n\n // 按时间戳降序(最新的在前)\n query = query.orderBy('checkpoint_ts', 'desc');\n\n const rows = await query.execute();\n let count = 0;\n\n for (const row of rows) {\n // 先反序列化 metadata 以便在应用层过滤\n const metadata = (await this.serde.loadsTyped(\n row.type ?? 'json',\n new TextDecoder().decode(row.metadata),\n )) as CheckpointMetadata;\n\n // 应用层 metadata 过滤(与 ShallowMemorySaver 保持一致)\n if (filter && !this._checkMetadataFilterMatch(metadata, filter as CheckpointMetadata)) {\n continue;\n }\n\n // 应用 limit\n if (limit !== undefined && count >= limit) {\n return;\n }\n\n const pendingWrites = await Promise.all(\n (JSON.parse(row.pending_writes || '[]') as Array<{\n task_id: string;\n channel: string;\n type: string;\n value: string;\n }>).map(async (write) => {\n return [\n write.task_id,\n write.channel,\n await this.serde.loadsTyped(write.type ?? 'json', write.value ?? ''),\n ] as [string, string, unknown];\n }),\n );\n\n const checkpoint = (await this.serde.loadsTyped(\n row.type ?? 'json',\n new TextDecoder().decode(row.checkpoint),\n )) as Checkpoint;\n\n if (checkpoint.v < 4 && row.parent_checkpoint_id != null) {\n await this.migratePendingSends(checkpoint, row.thread_id, row.parent_checkpoint_id);\n }\n\n count++;\n yield {\n config: {\n configurable: {\n thread_id: row.thread_id,\n checkpoint_ns: row.checkpoint_ns,\n checkpoint_id: row.checkpoint_id,\n },\n },\n checkpoint,\n metadata,\n parentConfig: row.parent_checkpoint_id\n ? {\n configurable: {\n thread_id: row.thread_id,\n checkpoint_ns: row.checkpoint_ns,\n checkpoint_id: row.parent_checkpoint_id,\n },\n }\n : undefined,\n pendingWrites,\n };\n }\n }\n\n /**\n * Check metadata filter matches (with deep comparison support)\n * Matches ShallowMemorySaver behavior\n */\n private _checkMetadataFilterMatch(metadata: any, filter: CheckpointMetadata): boolean {\n for (const [key, value] of Object.entries(filter)) {\n const metadataValue = metadata?.[key];\n\n if (value === null) {\n // For null filter value, check if key doesn't exist or value is null\n if (!(key in (metadata || {})) || metadataValue !== null) {\n return false;\n }\n } else if (typeof value === 'object' && !Array.isArray(value)) {\n // Deep comparison for objects with deterministic key ordering\n if (typeof metadataValue !== 'object' || metadataValue === null) {\n return false;\n }\n if (deterministicStringify(value) !== deterministicStringify(metadataValue)) {\n return false;\n }\n } else if (metadataValue !== value) {\n return false;\n }\n }\n return true;\n }\n\n async put(\n config: RunnableConfig,\n checkpoint: Checkpoint,\n metadata: CheckpointMetadata,\n _newVersions?: Record<string, string | number>,\n ): Promise<RunnableConfig> {\n await this.setup();\n\n const threadId = config.configurable?.thread_id;\n const checkpointNs = config.configurable?.checkpoint_ns ?? '';\n const parentCheckpointId = config.configurable?.checkpoint_id;\n\n if (!threadId) {\n throw new Error('thread_id is required');\n }\n\n // 使用 checkpoint.id 或生成新的\n const checkpointId = checkpoint.id || uuid6(0);\n\n const preparedCheckpoint: Partial<Checkpoint> = copyCheckpoint(checkpoint);\n\n // 序列化\n const [[type1, serializedCheckpoint], [type2, serializedMetadata]] = await Promise.all([\n this.serde.dumpsTyped(preparedCheckpoint),\n this.serde.dumpsTyped(metadata),\n ]);\n\n if (type1 !== type2) {\n throw new Error('Failed to serialize checkpoint and metadata to the same type.');\n }\n\n const threadId_ = threadId;\n const checkpointNs_ = checkpointNs;\n const checkpointId_ = checkpointId;\n\n // 带重试的数据库操作\n await withRetry(\n async () => {\n await this.db.transaction().execute(async (trx) => {\n // 获取旧的 checkpoint_id 用于清理 writes\n const oldCheckpoint = await trx\n .selectFrom('shallow_checkpoints')\n .select(['checkpoint_id'])\n .where('thread_id', '=', threadId_)\n .where('checkpoint_ns', '=', checkpointNs_)\n .executeTakeFirst();\n\n // 如果存在旧的 checkpoint 且 id 不同,清理旧的 writes\n if (oldCheckpoint && oldCheckpoint.checkpoint_id !== checkpointId_) {\n await trx\n .deleteFrom('writes')\n .where('thread_id', '=', threadId_)\n .where('checkpoint_ns', '=', checkpointNs_)\n .where('checkpoint_id', '=', oldCheckpoint.checkpoint_id)\n .execute();\n }\n\n // 使用 INSERT OR REPLACE (UPSERT) 覆盖写入\n await trx\n .insertInto('shallow_checkpoints')\n .values({\n thread_id: threadId_,\n checkpoint_ns: checkpointNs_,\n checkpoint_id: checkpointId_,\n parent_checkpoint_id: parentCheckpointId ?? null,\n type: type1,\n checkpoint: new Uint8Array(Buffer.from(serializedCheckpoint)),\n metadata: new Uint8Array(Buffer.from(serializedMetadata)),\n checkpoint_ts: Date.now(),\n })\n .onConflict((oc) =>\n oc.columns(['thread_id', 'checkpoint_ns']).doUpdateSet({\n checkpoint_id: checkpointId_,\n parent_checkpoint_id: parentCheckpointId ?? null,\n type: type1,\n checkpoint: new Uint8Array(Buffer.from(serializedCheckpoint)),\n metadata: new Uint8Array(Buffer.from(serializedMetadata)),\n checkpoint_ts: Date.now(),\n }),\n )\n .execute();\n });\n },\n `put(${threadId}/${checkpointId})`,\n );\n\n return {\n configurable: {\n thread_id: threadId,\n checkpoint_ns: checkpointNs,\n checkpoint_id: checkpointId,\n },\n };\n }\n\n async putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise<void> {\n await this.setup();\n\n const threadId = config.configurable?.thread_id;\n const checkpointNs = config.configurable?.checkpoint_ns ?? '';\n const checkpointId = config.configurable?.checkpoint_id;\n\n if (!threadId || !checkpointId) {\n throw new Error('thread_id and checkpoint_id are required');\n }\n\n // 预先序列化\n const values = await Promise.all(\n writes.map(async (write, idx) => {\n const [type, serializedWrite] = await this.serde.dumpsTyped(write[1]);\n return {\n thread_id: threadId,\n checkpoint_ns: checkpointNs,\n checkpoint_id: checkpointId,\n task_id: taskId,\n idx: WRITES_IDX_MAP[write[0]] ?? idx,\n channel: write[0],\n type,\n value: new Uint8Array(Buffer.from(serializedWrite)),\n };\n }),\n );\n\n if (values.length === 0) return;\n\n // 带重试的批量插入\n await withRetry(\n async () => {\n await this.db.transaction().execute(async (trx) => {\n // 先删除已存在的记录\n await trx\n .deleteFrom('writes')\n .where('thread_id', '=', threadId)\n .where('checkpoint_ns', '=', checkpointNs)\n .where('checkpoint_id', '=', checkpointId)\n .where('task_id', '=', taskId)\n .execute();\n\n // 批量插入\n for (const value of values) {\n await trx.insertInto('writes').values(value).execute();\n }\n });\n },\n `putWrites(${threadId}/${checkpointId}/${taskId})`,\n );\n }\n\n async deleteThread(threadId: string): Promise<void> {\n await withRetry(\n async () => {\n await this.db.transaction().execute(async (trx) => {\n await trx.deleteFrom('shallow_checkpoints').where('thread_id', '=', threadId).execute();\n await trx.deleteFrom('writes').where('thread_id', '=', threadId).execute();\n });\n },\n `deleteThread(${threadId})`,\n );\n }\n\n protected async migratePendingSends(checkpoint: Checkpoint, threadId: string, parentCheckpointId: string) {\n const result = await this.db\n .selectFrom('writes as ps')\n .select([\n 'ps.checkpoint_id',\n sql<string>`json_group_array(\n json_object(\n 'type', ps.type,\n 'value', CAST(ps.value AS TEXT)\n )\n )`.as('pending_sends'),\n ])\n .where('ps.thread_id', '=', threadId)\n .where('ps.checkpoint_id', '=', parentCheckpointId)\n .where('ps.channel', '=', TASKS)\n .orderBy('ps.idx')\n .executeTakeFirst();\n\n if (!result) return;\n\n const mutableCheckpoint = checkpoint;\n\n mutableCheckpoint.channel_values ??= {};\n mutableCheckpoint.channel_values[TASKS] = await Promise.all(\n JSON.parse(result.pending_sends || '[]').map(({ type, value }: { type: string; value: string }) =>\n this.serde.loadsTyped(type, value),\n ),\n );\n\n mutableCheckpoint.channel_versions[TASKS] =\n Object.keys(checkpoint.channel_versions).length > 0\n ? maxChannelVersion(...Object.values(checkpoint.channel_versions))\n : this.getNextVersion(undefined);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -42,8 +42,12 @@ class SQLiteAdapter {
|
|
|
42
42
|
return dbValue;
|
|
43
43
|
}
|
|
44
44
|
buildJsonQuery(db, field, key, value) {
|
|
45
|
-
const
|
|
46
|
-
|
|
45
|
+
const jsonPath = `$.${JSON.stringify(key)}`;
|
|
46
|
+
if (value === null) {
|
|
47
|
+
return sql`
|
|
48
|
+
json_type(${sql.ref(field)}, ${sql.lit(jsonPath)}) = 'null'
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
47
51
|
let compareValue;
|
|
48
52
|
if (typeof value === "string") {
|
|
49
53
|
compareValue = value;
|
|
@@ -51,18 +55,9 @@ class SQLiteAdapter {
|
|
|
51
55
|
compareValue = value;
|
|
52
56
|
} else if (typeof value === "boolean") {
|
|
53
57
|
compareValue = value ? 1 : 0;
|
|
54
|
-
} else if (value === null) {
|
|
55
|
-
compareValue = null;
|
|
56
58
|
} else {
|
|
57
59
|
compareValue = JSON.stringify(value);
|
|
58
60
|
}
|
|
59
|
-
if (value === null) {
|
|
60
|
-
const keyPattern = `"${key}":null`;
|
|
61
|
-
return sql`
|
|
62
|
-
json_extract(${sql.ref(field)}, ${sql.lit(jsonPath)}) IS NULL
|
|
63
|
-
AND ${sql.ref(field)} LIKE ${sql.lit(`%${keyPattern}%`)}
|
|
64
|
-
`;
|
|
65
|
-
}
|
|
66
61
|
return sql`json_extract(${sql.ref(field)}, ${sql.lit(jsonPath)}) = ${sql.lit(compareValue)}`;
|
|
67
62
|
}
|
|
68
63
|
now() {
|
|
@@ -105,4 +100,4 @@ class SQLiteAdapter {
|
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
export { SQLiteAdapter };
|
|
108
|
-
//# sourceMappingURL=sqlite-adapter-
|
|
103
|
+
//# sourceMappingURL=sqlite-adapter-CJXgit1j.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-adapter-CJXgit1j.js","sources":["../src/storage/kysely/sqlite-adapter.ts"],"sourcesContent":["import { Kysely, sql, SqlBool, Expression, SqliteDialect } from 'kysely';\nimport { DatabaseAdapter } from './adapter';\nimport { Database } from './types';\n\n/**\n * SQLite 适配器\n * - 时间类型:TEXT (ISO 8601 字符串)\n * - JSON 类型:TEXT\n * - JSON 查询:使用 json_extract 函数\n */\nexport class SQLiteAdapter implements DatabaseAdapter {\n db: Kysely<Database>;\n private pragmaPromise: Promise<void> | null = null;\n\n constructor(database: Kysely<any>) {\n this.db = database;\n }\n\n /**\n * 设置 SQLite PRAGMA 配置,解决锁问题\n * 使用 Promise 缓存确保并发安全且只执行一次\n */\n private ensurePragma(): Promise<void> {\n if (!this.pragmaPromise) {\n this.pragmaPromise = this.doEnsurePragma();\n }\n return this.pragmaPromise;\n }\n\n private async doEnsurePragma(): Promise<void> {\n // 锁等待超时 5 秒\n await sql`PRAGMA busy_timeout = 5000`.execute(this.db);\n // WAL 模式 - 读写并发\n await sql`PRAGMA journal_mode = WAL`.execute(this.db);\n // 平衡安全与性能\n await sql`PRAGMA synchronous = NORMAL`.execute(this.db);\n // 自动清理 WAL\n await sql`PRAGMA wal_autocheckpoint = 1000`.execute(this.db);\n }\n dateToDb(date: Date): string {\n // SQLite 存储为 ISO 8601 字符串\n return date.toISOString();\n }\n\n dbToDate(dbValue: any): Date {\n // SQLite 返回字符串,需要转换为 Date\n return new Date(dbValue);\n }\n\n jsonToDb(obj: any): string {\n // SQLite 存储为 JSON 字符串\n return JSON.stringify(obj);\n }\n\n dbToJson(dbValue: any): any {\n // SQLite 返回字符串,需要解析\n if (typeof dbValue === 'string') {\n try {\n return JSON.parse(dbValue);\n } catch {\n return dbValue;\n }\n }\n return dbValue;\n }\n\n buildJsonQuery(\n db: Kysely<Database>,\n field: 'metadata' | 'interrupts',\n key: string,\n value: any,\n ): Expression<SqlBool> {\n // SQLite json_extract 的行为:\n // - 字符串: 返回不带引号的文本\n // - 数字: 返回数字\n // - 布尔值: 返回 1/0\n // - null: 返回 NULL\n // 所以比较时需要根据类型处理\n\n // 构建 JSON 路径\n // 在 SQLite 中,所有键都需要用双引号括起来以确保正确解析\n // json_extract 语法: $.key 或 $.\"key-with-special\"\n const jsonPath = `$.${JSON.stringify(key)}`;\n\n // 构建 NULL 处理条件\n // 注意:SQLite 中 json_extract 对键不存在和值为 null 都返回 NULL\n // 使用 json_type 函数区分:\n // - 键不存在:json_type 返回 NULL\n // - 值为 null:json_type 返回 'null' 字符串\n if (value === null) {\n return sql<boolean>`\n json_type(${sql.ref(field)}, ${sql.lit(jsonPath)}) = 'null'\n `;\n }\n\n // 处理其他类型的值\n let compareValue: any;\n if (typeof value === 'string') {\n // 字符串: json_extract 返回不带引号的字符串,直接比较\n compareValue = value;\n } else if (typeof value === 'number') {\n // 数字: json_extract 返回数字\n compareValue = value;\n } else if (typeof value === 'boolean') {\n // 布尔值: json_extract 返回 1/0\n compareValue = value ? 1 : 0;\n } else {\n // 其他类型(对象、数组): 使用 JSON 字符串\n compareValue = JSON.stringify(value);\n }\n\n // 构建普通比较条件\n return sql<boolean>`json_extract(${sql.ref(field)}, ${sql.lit(jsonPath)}) = ${sql.lit(compareValue)}`;\n }\n\n now(): string {\n return new Date().toISOString();\n }\n\n async createTables(db: Kysely<Database>): Promise<void> {\n // 先设置 PRAGMA\n await this.ensurePragma();\n\n // 创建 threads 表\n await sql`\n CREATE TABLE IF NOT EXISTS threads (\n thread_id TEXT PRIMARY KEY,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n metadata TEXT NOT NULL DEFAULT '{}',\n status TEXT NOT NULL DEFAULT 'idle',\n \"values\" TEXT,\n interrupts TEXT NOT NULL DEFAULT '{}'\n )\n `.execute(db);\n\n // 创建 runs 表\n await sql`\n CREATE TABLE IF NOT EXISTS runs (\n run_id TEXT PRIMARY KEY,\n thread_id TEXT NOT NULL,\n assistant_id TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n metadata TEXT NOT NULL DEFAULT '{}',\n multitask_strategy TEXT NOT NULL DEFAULT 'reject',\n FOREIGN KEY (thread_id) REFERENCES threads(thread_id) ON DELETE CASCADE\n )\n `.execute(db);\n }\n\n async createIndexes(db: Kysely<Database>): Promise<void> {\n await sql`CREATE INDEX IF NOT EXISTS idx_threads_status ON threads(status)`.execute(db);\n await sql`CREATE INDEX IF NOT EXISTS idx_threads_created_at ON threads(created_at)`.execute(db);\n await sql`CREATE INDEX IF NOT EXISTS idx_threads_updated_at ON threads(updated_at)`.execute(db);\n await sql`CREATE INDEX IF NOT EXISTS idx_runs_thread_id ON runs(thread_id)`.execute(db);\n await sql`CREATE INDEX IF NOT EXISTS idx_runs_status ON runs(status)`.execute(db);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@ import { BaseStreamQueueInterface } from '../../queue/stream_queue.js';
|
|
|
4
4
|
/** 内存实现的消息队列,用于存储消息 */
|
|
5
5
|
export declare class MemoryStreamQueue extends BaseStreamQueue implements BaseStreamQueueInterface {
|
|
6
6
|
private data;
|
|
7
|
+
private activeGenerators;
|
|
8
|
+
private isDestroyed;
|
|
7
9
|
push(item: EventMessage): Promise<void>;
|
|
8
10
|
onDataChange(listener: (data: EventMessage) => void): () => void;
|
|
9
11
|
/**
|
|
@@ -15,4 +17,8 @@ export declare class MemoryStreamQueue extends BaseStreamQueue implements BaseSt
|
|
|
15
17
|
cancelSignal: AbortController;
|
|
16
18
|
cancel(): Promise<void>;
|
|
17
19
|
copyToQueue(toId: string, ttl?: number): Promise<MemoryStreamQueue>;
|
|
20
|
+
/**
|
|
21
|
+
* 销毁队列,释放所有资源
|
|
22
|
+
*/
|
|
23
|
+
destroy(): Promise<void>;
|
|
18
24
|
}
|
|
@@ -16,7 +16,16 @@ export declare class RedisStreamQueue extends BaseStreamQueue implements BaseStr
|
|
|
16
16
|
cancelSignal: AbortController;
|
|
17
17
|
private lastStreamId;
|
|
18
18
|
private pollInterval;
|
|
19
|
+
private connectionReady;
|
|
19
20
|
constructor(id: string, compressMessages?: boolean, ttl?: number);
|
|
21
|
+
/**
|
|
22
|
+
* 初始化 Redis 连接(使用共享连接池)
|
|
23
|
+
*/
|
|
24
|
+
private initConnection;
|
|
25
|
+
/**
|
|
26
|
+
* 确保连接已建立
|
|
27
|
+
*/
|
|
28
|
+
private ensureConnected;
|
|
20
29
|
/**
|
|
21
30
|
* 推送消息到 Redis Stream 和 List
|
|
22
31
|
* - Stream: 用于实时推送(集群友好)
|
|
@@ -34,7 +43,11 @@ export declare class RedisStreamQueue extends BaseStreamQueue implements BaseStr
|
|
|
34
43
|
/**
|
|
35
44
|
* 清空队列
|
|
36
45
|
*/
|
|
37
|
-
clear(): void
|
|
46
|
+
clear(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* 销毁队列实例,释放 Redis 连接引用
|
|
49
|
+
*/
|
|
50
|
+
destroy(): Promise<void>;
|
|
38
51
|
/**
|
|
39
52
|
* 取消操作
|
|
40
53
|
*/
|
|
@@ -321,11 +321,7 @@ class StreamQueueManager {
|
|
|
321
321
|
* @param id 队列 ID / Queue ID
|
|
322
322
|
*/
|
|
323
323
|
async cancelQueue(id) {
|
|
324
|
-
|
|
325
|
-
if (queue) {
|
|
326
|
-
await queue.cancel();
|
|
327
|
-
this.removeQueue(id);
|
|
328
|
-
}
|
|
324
|
+
await this.removeQueue(id);
|
|
329
325
|
}
|
|
330
326
|
/**
|
|
331
327
|
* 向指定 id 的队列推送数据
|
|
@@ -370,10 +366,32 @@ class StreamQueueManager {
|
|
|
370
366
|
* @param id 队列 ID / Queue ID
|
|
371
367
|
* @returns 是否成功删除 / Whether successfully deleted
|
|
372
368
|
*/
|
|
373
|
-
removeQueue(id) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
369
|
+
async removeQueue(id) {
|
|
370
|
+
const queue = this.queues.get(id);
|
|
371
|
+
if (!queue) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
await queue.cancel();
|
|
376
|
+
} catch (e) {
|
|
377
|
+
console.error("Error cancelling queue:", e);
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
const clearResult = queue.clear();
|
|
381
|
+
if (clearResult instanceof Promise) {
|
|
382
|
+
await clearResult;
|
|
383
|
+
}
|
|
384
|
+
} catch (e) {
|
|
385
|
+
console.error("Error clearing queue:", e);
|
|
386
|
+
}
|
|
387
|
+
if (typeof queue.destroy === "function") {
|
|
388
|
+
try {
|
|
389
|
+
await queue.destroy();
|
|
390
|
+
} catch (e) {
|
|
391
|
+
console.error("Error destroying queue:", e);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return this.queues.delete(id);
|
|
377
395
|
}
|
|
378
396
|
/**
|
|
379
397
|
* 获取所有队列的 ID
|
|
@@ -448,15 +466,29 @@ class KyselyThreadsManager {
|
|
|
448
466
|
}
|
|
449
467
|
async create(payload) {
|
|
450
468
|
const threadId = payload?.threadId || v7();
|
|
469
|
+
const now = /* @__PURE__ */ new Date();
|
|
470
|
+
const metadata = payload?.metadata || {};
|
|
471
|
+
const interrupts = {};
|
|
451
472
|
if (payload?.ifExists === "raise") {
|
|
452
473
|
const existing = await this.db.selectFrom("threads").select("thread_id").where("thread_id", "=", threadId).executeTakeFirst();
|
|
453
474
|
if (existing) {
|
|
454
475
|
throw new Error(`Thread with ID ${threadId} already exists.`);
|
|
455
476
|
}
|
|
456
477
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
478
|
+
if (payload?.ifExists === "do_nothing" && payload?.threadId) {
|
|
479
|
+
const existing = await this.db.selectFrom("threads").selectAll().where("thread_id", "=", threadId).executeTakeFirst();
|
|
480
|
+
if (existing) {
|
|
481
|
+
return {
|
|
482
|
+
thread_id: existing.thread_id,
|
|
483
|
+
created_at: this.adapter.dbToDate(existing.created_at).toISOString(),
|
|
484
|
+
updated_at: this.adapter.dbToDate(existing.updated_at).toISOString(),
|
|
485
|
+
metadata: this.adapter.dbToJson(existing.metadata),
|
|
486
|
+
status: existing.status,
|
|
487
|
+
values: existing.values ? this.adapter.dbToJson(existing.values) : null,
|
|
488
|
+
interrupts: this.adapter.dbToJson(existing.interrupts)
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
}
|
|
460
492
|
await this.db.insertInto("threads").values({
|
|
461
493
|
thread_id: threadId,
|
|
462
494
|
created_at: this.adapter.dateToDb(now),
|
|
@@ -596,10 +628,17 @@ class KyselyThreadsManager {
|
|
|
596
628
|
if (targetThread.status === "busy") {
|
|
597
629
|
throw new Error(`Thread with ID ${threadId} is busy, can't update state.`);
|
|
598
630
|
}
|
|
599
|
-
if (!targetThread.metadata?.graph_id) {
|
|
600
|
-
throw new Error(`Thread with ID ${threadId} has no graph_id.`);
|
|
601
|
-
}
|
|
602
631
|
const graphId = targetThread.metadata?.graph_id;
|
|
632
|
+
if (!graphId) {
|
|
633
|
+
await this.set(threadId, {
|
|
634
|
+
values: thread.values ?? null
|
|
635
|
+
});
|
|
636
|
+
return {
|
|
637
|
+
configurable: {
|
|
638
|
+
thread_id: threadId
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
}
|
|
603
642
|
const config = {
|
|
604
643
|
configurable: {
|
|
605
644
|
thread_id: threadId,
|
|
@@ -1146,13 +1185,19 @@ class StreamErrorEventMessage extends EventMessage {
|
|
|
1146
1185
|
|
|
1147
1186
|
class MemoryStreamQueue extends BaseStreamQueue {
|
|
1148
1187
|
data = [];
|
|
1188
|
+
activeGenerators = /* @__PURE__ */ new Set();
|
|
1189
|
+
isDestroyed = false;
|
|
1149
1190
|
async push(item) {
|
|
1191
|
+
if (this.isDestroyed) return;
|
|
1150
1192
|
const data = this.compressMessages ? await this.encodeData(item) : item;
|
|
1151
1193
|
this.data.push(data);
|
|
1152
1194
|
this.emit("dataChange", data);
|
|
1153
1195
|
}
|
|
1154
1196
|
onDataChange(listener) {
|
|
1197
|
+
if (this.isDestroyed) return () => {
|
|
1198
|
+
};
|
|
1155
1199
|
this.on("dataChange", async (item) => {
|
|
1200
|
+
if (this.isDestroyed) return;
|
|
1156
1201
|
listener(this.compressMessages ? await this.decodeData(item) : item);
|
|
1157
1202
|
});
|
|
1158
1203
|
return () => this.off("dataChange", listener);
|
|
@@ -1161,16 +1206,27 @@ class MemoryStreamQueue extends BaseStreamQueue {
|
|
|
1161
1206
|
* 异步生成器:支持 for await...of 方式消费队列数据
|
|
1162
1207
|
*/
|
|
1163
1208
|
async *onDataReceive() {
|
|
1164
|
-
|
|
1209
|
+
if (this.isDestroyed) {
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
const localAbortController = new AbortController();
|
|
1213
|
+
this.activeGenerators.add(localAbortController);
|
|
1214
|
+
let localQueue = [];
|
|
1165
1215
|
let pendingResolve = null;
|
|
1166
1216
|
let isStreamEnded = false;
|
|
1167
1217
|
let isCleanupDone = false;
|
|
1218
|
+
let endTimeoutId = null;
|
|
1168
1219
|
const handleData = async (item) => {
|
|
1220
|
+
if (isCleanupDone || localAbortController.signal.aborted) return;
|
|
1169
1221
|
try {
|
|
1170
1222
|
const data = this.compressMessages ? await this.decodeData(item) : item;
|
|
1171
|
-
|
|
1223
|
+
localQueue.push(data);
|
|
1172
1224
|
if (data.event === "__stream_end__" || data.event === "__stream_error__" || data.event === "__stream_cancel__") {
|
|
1173
|
-
|
|
1225
|
+
if (endTimeoutId) {
|
|
1226
|
+
clearTimeout(endTimeoutId);
|
|
1227
|
+
endTimeoutId = null;
|
|
1228
|
+
}
|
|
1229
|
+
endTimeoutId = setTimeout(() => {
|
|
1174
1230
|
isStreamEnded = true;
|
|
1175
1231
|
if (pendingResolve) {
|
|
1176
1232
|
pendingResolve();
|
|
@@ -1178,7 +1234,7 @@ class MemoryStreamQueue extends BaseStreamQueue {
|
|
|
1178
1234
|
}
|
|
1179
1235
|
}, 300);
|
|
1180
1236
|
if (data.event === "__stream_cancel__") {
|
|
1181
|
-
|
|
1237
|
+
localAbortController.abort("stream cancelled");
|
|
1182
1238
|
}
|
|
1183
1239
|
}
|
|
1184
1240
|
if (pendingResolve) {
|
|
@@ -1201,35 +1257,39 @@ class MemoryStreamQueue extends BaseStreamQueue {
|
|
|
1201
1257
|
pendingResolve = null;
|
|
1202
1258
|
}
|
|
1203
1259
|
};
|
|
1204
|
-
|
|
1260
|
+
localAbortController.signal.addEventListener("abort", abortHandler);
|
|
1205
1261
|
const cleanup = () => {
|
|
1206
1262
|
if (isCleanupDone) return;
|
|
1207
1263
|
isCleanupDone = true;
|
|
1264
|
+
if (endTimeoutId) {
|
|
1265
|
+
clearTimeout(endTimeoutId);
|
|
1266
|
+
endTimeoutId = null;
|
|
1267
|
+
}
|
|
1208
1268
|
try {
|
|
1209
1269
|
this.off("dataChange", handleData);
|
|
1210
1270
|
} catch (e) {
|
|
1211
|
-
console.error("Error removing dataChange listener:", e);
|
|
1212
1271
|
}
|
|
1213
1272
|
try {
|
|
1214
|
-
|
|
1273
|
+
localAbortController.signal.removeEventListener("abort", abortHandler);
|
|
1215
1274
|
} catch (e) {
|
|
1216
|
-
console.error("Error removing abort listener:", e);
|
|
1217
1275
|
}
|
|
1218
1276
|
if (pendingResolve) {
|
|
1219
1277
|
pendingResolve();
|
|
1220
1278
|
pendingResolve = null;
|
|
1221
1279
|
}
|
|
1280
|
+
localQueue.length = 0;
|
|
1281
|
+
this.activeGenerators.delete(localAbortController);
|
|
1222
1282
|
};
|
|
1223
1283
|
try {
|
|
1224
|
-
if (
|
|
1284
|
+
if (localAbortController.signal.aborted || this.isDestroyed) {
|
|
1225
1285
|
return;
|
|
1226
1286
|
}
|
|
1227
|
-
while (!isStreamEnded && !
|
|
1228
|
-
if (
|
|
1229
|
-
for (const item of
|
|
1287
|
+
while (!isStreamEnded && !localAbortController.signal.aborted && !this.isDestroyed) {
|
|
1288
|
+
if (localQueue.length > 0) {
|
|
1289
|
+
for (const item of localQueue) {
|
|
1230
1290
|
yield item;
|
|
1231
1291
|
}
|
|
1232
|
-
|
|
1292
|
+
localQueue.length = 0;
|
|
1233
1293
|
} else {
|
|
1234
1294
|
await new Promise((resolve) => {
|
|
1235
1295
|
pendingResolve = resolve;
|
|
@@ -1241,17 +1301,29 @@ class MemoryStreamQueue extends BaseStreamQueue {
|
|
|
1241
1301
|
}
|
|
1242
1302
|
}
|
|
1243
1303
|
async getAll() {
|
|
1304
|
+
if (this.isDestroyed) return [];
|
|
1244
1305
|
return this.compressMessages ? await Promise.all(
|
|
1245
1306
|
this.data.map((i) => this.decodeData(i))
|
|
1246
|
-
) : this.data;
|
|
1307
|
+
) : [...this.data];
|
|
1247
1308
|
}
|
|
1248
1309
|
clear() {
|
|
1249
|
-
this.data =
|
|
1310
|
+
this.data.length = 0;
|
|
1250
1311
|
}
|
|
1251
1312
|
cancelSignal = new AbortController();
|
|
1252
1313
|
async cancel() {
|
|
1253
|
-
|
|
1254
|
-
|
|
1314
|
+
for (const controller of this.activeGenerators) {
|
|
1315
|
+
try {
|
|
1316
|
+
controller.abort("user cancel this run");
|
|
1317
|
+
} catch (e) {
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
this.activeGenerators.clear();
|
|
1321
|
+
if (!this.cancelSignal.signal.aborted) {
|
|
1322
|
+
this.cancelSignal.abort("user cancel this run");
|
|
1323
|
+
}
|
|
1324
|
+
if (!this.isDestroyed) {
|
|
1325
|
+
await this.push(new CancelEventMessage());
|
|
1326
|
+
}
|
|
1255
1327
|
}
|
|
1256
1328
|
async copyToQueue(toId, ttl) {
|
|
1257
1329
|
const data = this.data.slice();
|
|
@@ -1259,6 +1331,17 @@ class MemoryStreamQueue extends BaseStreamQueue {
|
|
|
1259
1331
|
queue.data = data;
|
|
1260
1332
|
return queue;
|
|
1261
1333
|
}
|
|
1334
|
+
/**
|
|
1335
|
+
* 销毁队列,释放所有资源
|
|
1336
|
+
*/
|
|
1337
|
+
async destroy() {
|
|
1338
|
+
if (this.isDestroyed) return;
|
|
1339
|
+
this.isDestroyed = true;
|
|
1340
|
+
await this.cancel();
|
|
1341
|
+
this.clear();
|
|
1342
|
+
this.removeAllListeners();
|
|
1343
|
+
this.activeGenerators.clear();
|
|
1344
|
+
}
|
|
1262
1345
|
}
|
|
1263
1346
|
|
|
1264
1347
|
class MemoryThreadsManager {
|
|
@@ -1624,12 +1707,12 @@ const createCheckPointer = async () => {
|
|
|
1624
1707
|
if (process.env.SQLITE_DATABASE_URI) {
|
|
1625
1708
|
if (process.env.CHECKPOINT_TYPE === "sqlite") {
|
|
1626
1709
|
console.debug("LG | Using sqlite (full) as checkpoint");
|
|
1627
|
-
const { SqliteSaver } = await import('./checkpoint-
|
|
1710
|
+
const { SqliteSaver } = await import('./checkpoint-CY59Lr2q.js');
|
|
1628
1711
|
const db2 = await SqliteSaver.fromConnStringAsync(process.env.SQLITE_DATABASE_URI);
|
|
1629
1712
|
return db2;
|
|
1630
1713
|
}
|
|
1631
1714
|
console.debug("LG | Using shallow sqlite as checkpoint (default)");
|
|
1632
|
-
const { SqliteShallowSaver: SqliteShallowSaver2 } = await import('./shallow-checkpoint-
|
|
1715
|
+
const { SqliteShallowSaver: SqliteShallowSaver2 } = await import('./shallow-checkpoint-ImbLxYNR.js');
|
|
1633
1716
|
const db = await SqliteShallowSaver2.fromConnStringAsync(process.env.SQLITE_DATABASE_URI);
|
|
1634
1717
|
return db;
|
|
1635
1718
|
}
|
|
@@ -1648,7 +1731,7 @@ const createMessageQueue = async () => {
|
|
|
1648
1731
|
let q;
|
|
1649
1732
|
if (process.env.REDIS_URL) {
|
|
1650
1733
|
console.debug("LG | Using redis as stream queue");
|
|
1651
|
-
const { RedisStreamQueue } = await import('./queue-
|
|
1734
|
+
const { RedisStreamQueue } = await import('./queue-CUe5TDP1.js');
|
|
1652
1735
|
q = RedisStreamQueue;
|
|
1653
1736
|
} else {
|
|
1654
1737
|
q = MemoryStreamQueue;
|
|
@@ -1688,7 +1771,7 @@ const createThreadManager = async (config) => {
|
|
|
1688
1771
|
}
|
|
1689
1772
|
if (process.env.SQLITE_DATABASE_URI && config.checkpointer) {
|
|
1690
1773
|
console.debug("LG | Using SQLite ThreadsManager");
|
|
1691
|
-
const { SQLiteAdapter } = await import('./sqlite-adapter-
|
|
1774
|
+
const { SQLiteAdapter } = await import('./sqlite-adapter-CJXgit1j.js');
|
|
1692
1775
|
const database = config.checkpointer.db;
|
|
1693
1776
|
const threadsManager = new KyselyThreadsManager(new SQLiteAdapter(database));
|
|
1694
1777
|
await threadsManager.setup();
|
|
@@ -1734,7 +1817,7 @@ async function streamStateWithQueue(threads, run, queue, payload, options) {
|
|
|
1734
1817
|
const graph = await options.getGraph(graphId, payload.config, {
|
|
1735
1818
|
checkpointer: payload.temporary ? null : void 0
|
|
1736
1819
|
});
|
|
1737
|
-
const userStreamMode = payload.streamMode
|
|
1820
|
+
const userStreamMode = Array.isArray(payload.streamMode) ? payload.streamMode : payload.streamMode ? [payload.streamMode] : [];
|
|
1738
1821
|
const libStreamMode = /* @__PURE__ */ new Set([
|
|
1739
1822
|
"values",
|
|
1740
1823
|
...userStreamMode.filter((mode) => mode !== "events" && mode !== "messages-tuple")
|
|
@@ -1756,27 +1839,28 @@ async function streamStateWithQueue(threads, run, queue, payload, options) {
|
|
|
1756
1839
|
...payload.config?.metadata,
|
|
1757
1840
|
run_attempt: options.attempt
|
|
1758
1841
|
};
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
interruptAfter: payload.interruptAfter,
|
|
1763
|
-
interruptBefore: payload.interruptBefore,
|
|
1764
|
-
tags: payload.config?.tags,
|
|
1765
|
-
configurable: payload.config?.configurable,
|
|
1766
|
-
recursionLimit: payload.config?.recursionLimit,
|
|
1767
|
-
subgraphs: payload.streamSubgraphs,
|
|
1768
|
-
metadata,
|
|
1769
|
-
runId: run.run_id,
|
|
1770
|
-
streamMode: [...libStreamMode],
|
|
1771
|
-
signal: queue.cancelSignal.signal
|
|
1772
|
-
}
|
|
1773
|
-
);
|
|
1774
|
-
let sendedMetadataMessage;
|
|
1775
|
-
let messageChunks;
|
|
1842
|
+
let sendedMetadataMessage = null;
|
|
1843
|
+
let messageChunks = null;
|
|
1844
|
+
let eventsIterator = null;
|
|
1776
1845
|
try {
|
|
1777
1846
|
sendedMetadataMessage = /* @__PURE__ */ new Set();
|
|
1778
1847
|
messageChunks = /* @__PURE__ */ new Map();
|
|
1779
|
-
|
|
1848
|
+
eventsIterator = await graph.stream(
|
|
1849
|
+
payload.command != null ? getLangGraphCommand(payload.command) : payload.input ?? null,
|
|
1850
|
+
{
|
|
1851
|
+
interruptAfter: payload.interruptAfter,
|
|
1852
|
+
interruptBefore: payload.interruptBefore,
|
|
1853
|
+
tags: payload.config?.tags,
|
|
1854
|
+
configurable: payload.config?.configurable,
|
|
1855
|
+
recursionLimit: payload.config?.recursionLimit,
|
|
1856
|
+
subgraphs: payload.streamSubgraphs,
|
|
1857
|
+
metadata,
|
|
1858
|
+
runId: run.run_id,
|
|
1859
|
+
streamMode: [...libStreamMode],
|
|
1860
|
+
signal: queue.cancelSignal.signal
|
|
1861
|
+
}
|
|
1862
|
+
);
|
|
1863
|
+
for await (const event of eventsIterator) {
|
|
1780
1864
|
let ns = [];
|
|
1781
1865
|
if (event.length === 3) {
|
|
1782
1866
|
ns = event.splice(0, 1);
|
|
@@ -1828,14 +1912,29 @@ async function streamStateWithQueue(threads, run, queue, payload, options) {
|
|
|
1828
1912
|
await queue.push(new EventMessage(getNameWithNs("updates"), updates));
|
|
1829
1913
|
}
|
|
1830
1914
|
}
|
|
1915
|
+
} catch (error) {
|
|
1916
|
+
if (!(error instanceof Error && error.message?.includes("cancel"))) {
|
|
1917
|
+
console.error("streamStateWithQueue error:", error);
|
|
1918
|
+
try {
|
|
1919
|
+
await queue.push(new StreamErrorEventMessage(error));
|
|
1920
|
+
} catch (e) {
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
throw error;
|
|
1831
1924
|
} finally {
|
|
1832
|
-
|
|
1925
|
+
try {
|
|
1926
|
+
await queue.push(new StreamEndEventMessage());
|
|
1927
|
+
} catch (e) {
|
|
1928
|
+
}
|
|
1833
1929
|
if (sendedMetadataMessage) {
|
|
1834
1930
|
sendedMetadataMessage.clear();
|
|
1931
|
+
sendedMetadataMessage = null;
|
|
1835
1932
|
}
|
|
1836
1933
|
if (messageChunks) {
|
|
1837
1934
|
messageChunks.clear();
|
|
1935
|
+
messageChunks = null;
|
|
1838
1936
|
}
|
|
1937
|
+
eventsIterator = null;
|
|
1839
1938
|
}
|
|
1840
1939
|
}
|
|
1841
1940
|
const serialiseAsDict = (obj, indent = 0) => {
|
|
@@ -1856,12 +1955,17 @@ async function* streamState(threads, run, payload, options) {
|
|
|
1856
1955
|
run = await run;
|
|
1857
1956
|
const queueId = run.run_id;
|
|
1858
1957
|
const threadId = run.thread_id;
|
|
1958
|
+
let state = null;
|
|
1959
|
+
let queue = null;
|
|
1960
|
+
let backgroundTask = null;
|
|
1961
|
+
let isCleaningUp = false;
|
|
1859
1962
|
try {
|
|
1860
1963
|
await threads.set(threadId, { status: "busy" });
|
|
1861
1964
|
await threads.updateRun(run.run_id, { status: "running" });
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
streamStateWithQueue(threads, run, queue, payload, options).catch((error) => {
|
|
1965
|
+
queue = LangGraphGlobal.globalMessageQueue.createQueue(queueId);
|
|
1966
|
+
state = queue.onDataReceive();
|
|
1967
|
+
backgroundTask = streamStateWithQueue(threads, run, queue, payload, options).catch((error) => {
|
|
1968
|
+
if (isCleaningUp) return;
|
|
1865
1969
|
if (error.message !== "user cancel this run") console.error("Queue task error:", error);
|
|
1866
1970
|
LangGraphGlobal.globalMessageQueue.pushToQueue(queueId, new StreamErrorEventMessage(error));
|
|
1867
1971
|
});
|
|
@@ -1874,16 +1978,40 @@ async function* streamState(threads, run, payload, options) {
|
|
|
1874
1978
|
await threads.updateRun(run.run_id, { status: "error" });
|
|
1875
1979
|
await threads.set(threadId, { status: "error" });
|
|
1876
1980
|
} finally {
|
|
1981
|
+
isCleaningUp = true;
|
|
1982
|
+
if (state) {
|
|
1983
|
+
try {
|
|
1984
|
+
await state.return(void 0);
|
|
1985
|
+
} catch (e) {
|
|
1986
|
+
}
|
|
1987
|
+
state = null;
|
|
1988
|
+
}
|
|
1989
|
+
if (queue && !queue.cancelSignal.signal.aborted) {
|
|
1990
|
+
try {
|
|
1991
|
+
queue.cancelSignal.abort("Stream consumer disconnected");
|
|
1992
|
+
} catch (e) {
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
if (backgroundTask) {
|
|
1996
|
+
try {
|
|
1997
|
+
await Promise.race([
|
|
1998
|
+
backgroundTask,
|
|
1999
|
+
new Promise((resolve) => setTimeout(resolve, 1e3))
|
|
2000
|
+
]);
|
|
2001
|
+
} catch (e) {
|
|
2002
|
+
}
|
|
2003
|
+
backgroundTask = null;
|
|
2004
|
+
}
|
|
1877
2005
|
const nowState = await threads.get(threadId);
|
|
1878
2006
|
if (nowState.status === "interrupted") {
|
|
1879
2007
|
await LangGraphGlobal.globalMessageQueue.copyQueue(queueId, threadId, 3e4);
|
|
1880
2008
|
} else {
|
|
1881
2009
|
await threads.set(threadId, { status: "idle", interrupts: {} });
|
|
1882
2010
|
}
|
|
1883
|
-
await LangGraphGlobal.globalMessageQueue.
|
|
1884
|
-
|
|
2011
|
+
await LangGraphGlobal.globalMessageQueue.removeQueue(queueId);
|
|
2012
|
+
queue = null;
|
|
1885
2013
|
}
|
|
1886
2014
|
}
|
|
1887
2015
|
|
|
1888
2016
|
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 };
|
|
1889
|
-
//# sourceMappingURL=stream-
|
|
2017
|
+
//# sourceMappingURL=stream-jYlUzTZO.js.map
|