@axiom-lattice/core 1.0.50 → 2.0.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.
package/dist/index.d.mts CHANGED
@@ -13,6 +13,7 @@ import * as _langchain_core_tools from '@langchain/core/tools';
13
13
  import { StructuredTool } from '@langchain/core/tools';
14
14
  import { CompiledStateGraph } from '@langchain/langgraph';
15
15
  import { BaseCheckpointSaver } from '@langchain/langgraph-checkpoint';
16
+ import { ReplaySubject } from 'rxjs';
16
17
 
17
18
  /**
18
19
  * BaseLatticeManager - 抽象基类,为各种Lattice管理器提供通用功能
@@ -476,7 +477,7 @@ interface ThreadBufferConfig {
476
477
  */
477
478
  interface ThreadBuffer {
478
479
  threadId: string;
479
- chunks: MessageChunk[];
480
+ chunks$: ReplaySubject<MessageChunk>;
480
481
  status: ThreadStatus;
481
482
  createdAt: number;
482
483
  updatedAt: number;
@@ -490,7 +491,6 @@ interface BufferStats {
490
491
  activeThreads: number;
491
492
  completedThreads: number;
492
493
  abortedThreads: number;
493
- totalChunks: number;
494
494
  config: Required<ThreadBufferConfig>;
495
495
  }
496
496
 
@@ -506,18 +506,6 @@ declare abstract class ChunkBuffer {
506
506
  * Chunks are appended in order
507
507
  */
508
508
  abstract addChunk(threadId: string, content: MessageChunk): Promise<void>;
509
- /**
510
- * Get all chunks for a thread in order
511
- */
512
- abstract getChunks(threadId: string): Promise<MessageChunk[]>;
513
- /**
514
- * Get accumulated content for a thread (all chunks concatenated)
515
- */
516
- abstract getAccumulatedContent(threadId: string): Promise<string>;
517
- /**
518
- * Get chunks for a specific message within a thread
519
- */
520
- abstract getChunksByMessageId(threadId: string, messageId: string): Promise<MessageChunk[]>;
521
509
  /**
522
510
  * Mark thread as completed (explicit call)
523
511
  */
@@ -563,12 +551,7 @@ declare abstract class ChunkBuffer {
563
551
  * Check if a thread exists (valid or expired)
564
552
  */
565
553
  abstract hasThread(threadId: string): Promise<boolean>;
566
- /**
567
- * Get new chunks since known content
568
- * Used for resuming streams from a known position
569
- * Matches the known content and returns chunks after that position
570
- */
571
- abstract getNewChunksSinceContent(threadId: string, messageId: string, knownContent: string): AsyncGenerator<MessageChunk>;
554
+ abstract getNewChunksSinceContentIterator(threadId: string, messageId: string, knownContent: string): AsyncIterable<MessageChunk>;
572
555
  }
573
556
 
574
557
  /**
@@ -583,7 +566,9 @@ declare class InMemoryChunkBuffer extends ChunkBuffer {
583
566
  private buffers;
584
567
  private config;
585
568
  private cleanupTimer?;
586
- constructor(config?: ThreadBufferConfig);
569
+ constructor(config?: ThreadBufferConfig & {
570
+ maxChunks?: number;
571
+ });
587
572
  /**
588
573
  * Start automatic periodic cleanup timer
589
574
  */
@@ -605,9 +590,6 @@ declare class InMemoryChunkBuffer extends ChunkBuffer {
605
590
  */
606
591
  private getOrCreateBuffer;
607
592
  addChunk(threadId: string, content: MessageChunk): Promise<void>;
608
- getChunks(threadId: string): Promise<MessageChunk[]>;
609
- getAccumulatedContent(threadId: string): Promise<string>;
610
- getChunksByMessageId(threadId: string, messageId: string): Promise<MessageChunk[]>;
611
593
  completeThread(threadId: string): Promise<void>;
612
594
  abortThread(threadId: string): Promise<void>;
613
595
  isThreadActive(threadId: string): Promise<boolean>;
@@ -622,24 +604,9 @@ declare class InMemoryChunkBuffer extends ChunkBuffer {
622
604
  * Returns number of threads cleaned up
623
605
  */
624
606
  cleanupExpiredThreads(): Promise<number>;
625
- /**
626
- * Extend thread TTL
627
- */
628
607
  extendThreadTTL(threadId: string, additionalMs?: number): Promise<void>;
629
- /**
630
- * Get new chunks since known content
631
- * Used for resuming streams from a known position
632
- * Matches the known content and returns chunks after that position
633
- * Continues to yield new chunks as they are added until thread completes/aborts
634
- */
635
- getNewChunksSinceContent(threadId: string, messageId: string, knownContent: string): AsyncGenerator<MessageChunk>;
636
- /**
637
- * Get statistics about the buffer
638
- */
608
+ getNewChunksSinceContentIterator(threadId: string, messageId: string, knownContent: string): AsyncIterable<MessageChunk>;
639
609
  getStats(): BufferStats;
640
- /**
641
- * Cleanup method for graceful shutdown
642
- */
643
610
  dispose(): void;
644
611
  }
645
612
 
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ import * as _langchain_core_tools from '@langchain/core/tools';
13
13
  import { StructuredTool } from '@langchain/core/tools';
14
14
  import { CompiledStateGraph } from '@langchain/langgraph';
15
15
  import { BaseCheckpointSaver } from '@langchain/langgraph-checkpoint';
16
+ import { ReplaySubject } from 'rxjs';
16
17
 
17
18
  /**
18
19
  * BaseLatticeManager - 抽象基类,为各种Lattice管理器提供通用功能
@@ -476,7 +477,7 @@ interface ThreadBufferConfig {
476
477
  */
477
478
  interface ThreadBuffer {
478
479
  threadId: string;
479
- chunks: MessageChunk[];
480
+ chunks$: ReplaySubject<MessageChunk>;
480
481
  status: ThreadStatus;
481
482
  createdAt: number;
482
483
  updatedAt: number;
@@ -490,7 +491,6 @@ interface BufferStats {
490
491
  activeThreads: number;
491
492
  completedThreads: number;
492
493
  abortedThreads: number;
493
- totalChunks: number;
494
494
  config: Required<ThreadBufferConfig>;
495
495
  }
496
496
 
@@ -506,18 +506,6 @@ declare abstract class ChunkBuffer {
506
506
  * Chunks are appended in order
507
507
  */
508
508
  abstract addChunk(threadId: string, content: MessageChunk): Promise<void>;
509
- /**
510
- * Get all chunks for a thread in order
511
- */
512
- abstract getChunks(threadId: string): Promise<MessageChunk[]>;
513
- /**
514
- * Get accumulated content for a thread (all chunks concatenated)
515
- */
516
- abstract getAccumulatedContent(threadId: string): Promise<string>;
517
- /**
518
- * Get chunks for a specific message within a thread
519
- */
520
- abstract getChunksByMessageId(threadId: string, messageId: string): Promise<MessageChunk[]>;
521
509
  /**
522
510
  * Mark thread as completed (explicit call)
523
511
  */
@@ -563,12 +551,7 @@ declare abstract class ChunkBuffer {
563
551
  * Check if a thread exists (valid or expired)
564
552
  */
565
553
  abstract hasThread(threadId: string): Promise<boolean>;
566
- /**
567
- * Get new chunks since known content
568
- * Used for resuming streams from a known position
569
- * Matches the known content and returns chunks after that position
570
- */
571
- abstract getNewChunksSinceContent(threadId: string, messageId: string, knownContent: string): AsyncGenerator<MessageChunk>;
554
+ abstract getNewChunksSinceContentIterator(threadId: string, messageId: string, knownContent: string): AsyncIterable<MessageChunk>;
572
555
  }
573
556
 
574
557
  /**
@@ -583,7 +566,9 @@ declare class InMemoryChunkBuffer extends ChunkBuffer {
583
566
  private buffers;
584
567
  private config;
585
568
  private cleanupTimer?;
586
- constructor(config?: ThreadBufferConfig);
569
+ constructor(config?: ThreadBufferConfig & {
570
+ maxChunks?: number;
571
+ });
587
572
  /**
588
573
  * Start automatic periodic cleanup timer
589
574
  */
@@ -605,9 +590,6 @@ declare class InMemoryChunkBuffer extends ChunkBuffer {
605
590
  */
606
591
  private getOrCreateBuffer;
607
592
  addChunk(threadId: string, content: MessageChunk): Promise<void>;
608
- getChunks(threadId: string): Promise<MessageChunk[]>;
609
- getAccumulatedContent(threadId: string): Promise<string>;
610
- getChunksByMessageId(threadId: string, messageId: string): Promise<MessageChunk[]>;
611
593
  completeThread(threadId: string): Promise<void>;
612
594
  abortThread(threadId: string): Promise<void>;
613
595
  isThreadActive(threadId: string): Promise<boolean>;
@@ -622,24 +604,9 @@ declare class InMemoryChunkBuffer extends ChunkBuffer {
622
604
  * Returns number of threads cleaned up
623
605
  */
624
606
  cleanupExpiredThreads(): Promise<number>;
625
- /**
626
- * Extend thread TTL
627
- */
628
607
  extendThreadTTL(threadId: string, additionalMs?: number): Promise<void>;
629
- /**
630
- * Get new chunks since known content
631
- * Used for resuming streams from a known position
632
- * Matches the known content and returns chunks after that position
633
- * Continues to yield new chunks as they are added until thread completes/aborts
634
- */
635
- getNewChunksSinceContent(threadId: string, messageId: string, knownContent: string): AsyncGenerator<MessageChunk>;
636
- /**
637
- * Get statistics about the buffer
638
- */
608
+ getNewChunksSinceContentIterator(threadId: string, messageId: string, knownContent: string): AsyncIterable<MessageChunk>;
639
609
  getStats(): BufferStats;
640
- /**
641
- * Cleanup method for graceful shutdown
642
- */
643
610
  dispose(): void;
644
611
  }
645
612
 
package/dist/index.js CHANGED
@@ -2253,13 +2253,16 @@ var ThreadStatus = /* @__PURE__ */ ((ThreadStatus2) => {
2253
2253
  })(ThreadStatus || {});
2254
2254
 
2255
2255
  // src/chunk_buffer_lattice/InMemoryChunkBuffer.ts
2256
+ var import_rxjs = require("rxjs");
2256
2257
  var InMemoryChunkBuffer = class extends ChunkBuffer {
2257
2258
  constructor(config) {
2258
2259
  super();
2259
2260
  this.buffers = /* @__PURE__ */ new Map();
2260
2261
  this.config = {
2261
2262
  ttl: config?.ttl ?? 60 * 60 * 1e3,
2262
- cleanupInterval: config?.cleanupInterval ?? 0
2263
+ cleanupInterval: config?.cleanupInterval ?? 0,
2264
+ maxChunks: config?.maxChunks ?? 1e3
2265
+ // Default max chunks per thread
2263
2266
  };
2264
2267
  if (this.config.cleanupInterval > 0) {
2265
2268
  this.startCleanupTimer();
@@ -2308,11 +2311,14 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2308
2311
  */
2309
2312
  getOrCreateBuffer(threadId) {
2310
2313
  let buffer = this.getBufferIfValid(threadId);
2314
+ 4;
2311
2315
  if (!buffer) {
2312
2316
  const now = Date.now();
2313
2317
  buffer = {
2314
2318
  threadId,
2315
- chunks: [],
2319
+ chunks$: new import_rxjs.ReplaySubject(
2320
+ this.config.maxChunks ?? 1e4
2321
+ ),
2316
2322
  status: "active" /* ACTIVE */,
2317
2323
  createdAt: now,
2318
2324
  updatedAt: now,
@@ -2320,34 +2326,30 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2320
2326
  };
2321
2327
  this.buffers.set(threadId, buffer);
2322
2328
  }
2329
+ if (buffer.status !== "active" /* ACTIVE */) {
2330
+ buffer.status = "active" /* ACTIVE */;
2331
+ buffer.chunks$ = new import_rxjs.ReplaySubject(
2332
+ this.config.maxChunks ?? 1e4
2333
+ );
2334
+ buffer.updatedAt = Date.now();
2335
+ buffer.expiresAt = Date.now() + this.config.ttl;
2336
+ }
2323
2337
  return buffer;
2324
2338
  }
2325
2339
  async addChunk(threadId, content) {
2326
2340
  const buffer = this.getOrCreateBuffer(threadId);
2327
2341
  const chunk = content;
2328
- buffer.chunks.push(chunk);
2342
+ buffer.chunks$.next(chunk);
2329
2343
  buffer.updatedAt = Date.now();
2330
2344
  buffer.expiresAt = Date.now() + this.config.ttl;
2331
- }
2332
- async getChunks(threadId) {
2333
- const buffer = this.getBufferIfValid(threadId);
2334
- return buffer ? [...buffer.chunks] : [];
2335
- }
2336
- async getAccumulatedContent(threadId) {
2337
- const buffer = this.getBufferIfValid(threadId);
2338
- if (!buffer) return "";
2339
- return buffer.chunks.map((chunk) => chunk.data?.content).join("");
2340
- }
2341
- async getChunksByMessageId(threadId, messageId) {
2342
- const buffer = this.getBufferIfValid(threadId);
2343
- if (!buffer) return [];
2344
- return buffer.chunks.filter((chunk) => chunk.data?.id === messageId);
2345
+ buffer.status = "active" /* ACTIVE */;
2345
2346
  }
2346
2347
  async completeThread(threadId) {
2347
2348
  const buffer = this.getBufferIfValid(threadId);
2348
2349
  if (buffer) {
2349
2350
  buffer.status = "completed" /* COMPLETED */;
2350
2351
  buffer.updatedAt = Date.now();
2352
+ buffer.chunks$.complete();
2351
2353
  }
2352
2354
  }
2353
2355
  async abortThread(threadId) {
@@ -2355,6 +2357,7 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2355
2357
  if (buffer) {
2356
2358
  buffer.status = "aborted" /* ABORTED */;
2357
2359
  buffer.updatedAt = Date.now();
2360
+ buffer.chunks$.error(new Error("Thread aborted"));
2358
2361
  }
2359
2362
  }
2360
2363
  async isThreadActive(threadId) {
@@ -2367,10 +2370,7 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2367
2370
  async getThreadBuffer(threadId) {
2368
2371
  const buffer = this.getBufferIfValid(threadId);
2369
2372
  if (!buffer) return void 0;
2370
- return {
2371
- ...buffer,
2372
- chunks: [...buffer.chunks]
2373
- };
2373
+ return buffer;
2374
2374
  }
2375
2375
  async clearThread(threadId) {
2376
2376
  this.buffers.delete(threadId);
@@ -2417,9 +2417,6 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2417
2417
  }
2418
2418
  return cleanedCount;
2419
2419
  }
2420
- /**
2421
- * Extend thread TTL
2422
- */
2423
2420
  async extendThreadTTL(threadId, additionalMs) {
2424
2421
  const buffer = this.getBufferIfValid(threadId);
2425
2422
  if (buffer) {
@@ -2428,62 +2425,69 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2428
2425
  buffer.updatedAt = Date.now();
2429
2426
  }
2430
2427
  }
2431
- /**
2432
- * Get new chunks since known content
2433
- * Used for resuming streams from a known position
2434
- * Matches the known content and returns chunks after that position
2435
- * Continues to yield new chunks as they are added until thread completes/aborts
2436
- */
2437
- async *getNewChunksSinceContent(threadId, messageId, knownContent) {
2438
- let buffer = this.getBufferIfValid(threadId);
2428
+ async *getNewChunksSinceContentIterator(threadId, messageId, knownContent) {
2429
+ const buffer = this.getBufferIfValid(threadId);
2439
2430
  if (!buffer) return;
2440
- let lastYieldedIndex = -1;
2441
2431
  let accumulatedContent = "";
2442
- for (let i = 0; i < buffer.chunks.length; i++) {
2443
- const chunk = buffer.chunks[i];
2444
- if (chunk.data?.id === messageId) {
2445
- accumulatedContent += chunk.data?.content || "";
2446
- if (accumulatedContent === knownContent) {
2447
- lastYieldedIndex = i;
2448
- break;
2432
+ const queue = [];
2433
+ let resolveNext = null;
2434
+ let errorNext = null;
2435
+ let isCompleted = false;
2436
+ const subscription = buffer.chunks$.subscribe({
2437
+ next: (chunk) => {
2438
+ queue.push(chunk);
2439
+ if (resolveNext) {
2440
+ const resolve = resolveNext;
2441
+ resolveNext = null;
2442
+ resolve();
2449
2443
  }
2450
- if (accumulatedContent.length > knownContent.length) {
2451
- if (accumulatedContent.startsWith(knownContent)) {
2452
- lastYieldedIndex = i;
2453
- break;
2454
- }
2444
+ },
2445
+ error: (err) => {
2446
+ if (errorNext) {
2447
+ const reject = errorNext;
2448
+ errorNext = null;
2449
+ reject(err);
2455
2450
  }
2456
- }
2457
- }
2458
- const pollingInterval = 100;
2459
- while (true) {
2460
- buffer = this.getBufferIfValid(threadId);
2461
- if (!buffer) break;
2462
- let hasNewChunks = false;
2463
- for (let i = lastYieldedIndex + 1; i < buffer.chunks.length; i++) {
2464
- const chunk = buffer.chunks[i];
2465
- if (chunk.data?.id === messageId) {
2466
- yield chunk;
2467
- lastYieldedIndex = i;
2468
- hasNewChunks = true;
2451
+ },
2452
+ complete: () => {
2453
+ isCompleted = true;
2454
+ if (resolveNext) {
2455
+ const resolve = resolveNext;
2456
+ resolveNext = null;
2457
+ resolve();
2469
2458
  }
2470
2459
  }
2471
- if (buffer.status === "completed" /* COMPLETED */ || buffer.status === "aborted" /* ABORTED */) {
2472
- break;
2473
- }
2474
- if (!hasNewChunks) {
2475
- await new Promise((resolve) => setTimeout(resolve, pollingInterval));
2460
+ });
2461
+ try {
2462
+ while (true) {
2463
+ if (queue.length === 0) {
2464
+ if (isCompleted) break;
2465
+ await new Promise((resolve, reject) => {
2466
+ resolveNext = resolve;
2467
+ errorNext = reject;
2468
+ });
2469
+ }
2470
+ while (queue.length > 0) {
2471
+ const chunk = queue.shift();
2472
+ if (!chunk) continue;
2473
+ if (chunk.data?.id === messageId) {
2474
+ accumulatedContent += chunk.data?.content || "";
2475
+ }
2476
+ if (accumulatedContent.length > knownContent.length) {
2477
+ if (accumulatedContent.startsWith(knownContent)) {
2478
+ yield chunk;
2479
+ }
2480
+ }
2481
+ }
2476
2482
  }
2483
+ } finally {
2484
+ subscription.unsubscribe();
2477
2485
  }
2478
2486
  }
2479
- /**
2480
- * Get statistics about the buffer
2481
- */
2482
2487
  getStats() {
2483
2488
  let activeCount = 0;
2484
2489
  let completedCount = 0;
2485
2490
  let abortedCount = 0;
2486
- let totalChunks = 0;
2487
2491
  const validBuffers = [];
2488
2492
  for (const [threadId, buffer] of this.buffers.entries()) {
2489
2493
  if (this.isExpired(buffer)) {
@@ -2493,7 +2497,6 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2493
2497
  }
2494
2498
  }
2495
2499
  for (const buffer of validBuffers) {
2496
- totalChunks += buffer.chunks.length;
2497
2500
  switch (buffer.status) {
2498
2501
  case "active" /* ACTIVE */:
2499
2502
  activeCount++;
@@ -2511,13 +2514,9 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2511
2514
  activeThreads: activeCount,
2512
2515
  completedThreads: completedCount,
2513
2516
  abortedThreads: abortedCount,
2514
- totalChunks,
2515
2517
  config: this.config
2516
2518
  };
2517
2519
  }
2518
- /**
2519
- * Cleanup method for graceful shutdown
2520
- */
2521
2520
  dispose() {
2522
2521
  this.stopCleanupTimer();
2523
2522
  this.buffers.clear();