@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.mjs CHANGED
@@ -2205,13 +2205,16 @@ var ThreadStatus = /* @__PURE__ */ ((ThreadStatus2) => {
2205
2205
  })(ThreadStatus || {});
2206
2206
 
2207
2207
  // src/chunk_buffer_lattice/InMemoryChunkBuffer.ts
2208
+ import { ReplaySubject } from "rxjs";
2208
2209
  var InMemoryChunkBuffer = class extends ChunkBuffer {
2209
2210
  constructor(config) {
2210
2211
  super();
2211
2212
  this.buffers = /* @__PURE__ */ new Map();
2212
2213
  this.config = {
2213
2214
  ttl: config?.ttl ?? 60 * 60 * 1e3,
2214
- cleanupInterval: config?.cleanupInterval ?? 0
2215
+ cleanupInterval: config?.cleanupInterval ?? 0,
2216
+ maxChunks: config?.maxChunks ?? 1e3
2217
+ // Default max chunks per thread
2215
2218
  };
2216
2219
  if (this.config.cleanupInterval > 0) {
2217
2220
  this.startCleanupTimer();
@@ -2260,11 +2263,14 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2260
2263
  */
2261
2264
  getOrCreateBuffer(threadId) {
2262
2265
  let buffer = this.getBufferIfValid(threadId);
2266
+ 4;
2263
2267
  if (!buffer) {
2264
2268
  const now = Date.now();
2265
2269
  buffer = {
2266
2270
  threadId,
2267
- chunks: [],
2271
+ chunks$: new ReplaySubject(
2272
+ this.config.maxChunks ?? 1e4
2273
+ ),
2268
2274
  status: "active" /* ACTIVE */,
2269
2275
  createdAt: now,
2270
2276
  updatedAt: now,
@@ -2272,34 +2278,30 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2272
2278
  };
2273
2279
  this.buffers.set(threadId, buffer);
2274
2280
  }
2281
+ if (buffer.status !== "active" /* ACTIVE */) {
2282
+ buffer.status = "active" /* ACTIVE */;
2283
+ buffer.chunks$ = new ReplaySubject(
2284
+ this.config.maxChunks ?? 1e4
2285
+ );
2286
+ buffer.updatedAt = Date.now();
2287
+ buffer.expiresAt = Date.now() + this.config.ttl;
2288
+ }
2275
2289
  return buffer;
2276
2290
  }
2277
2291
  async addChunk(threadId, content) {
2278
2292
  const buffer = this.getOrCreateBuffer(threadId);
2279
2293
  const chunk = content;
2280
- buffer.chunks.push(chunk);
2294
+ buffer.chunks$.next(chunk);
2281
2295
  buffer.updatedAt = Date.now();
2282
2296
  buffer.expiresAt = Date.now() + this.config.ttl;
2283
- }
2284
- async getChunks(threadId) {
2285
- const buffer = this.getBufferIfValid(threadId);
2286
- return buffer ? [...buffer.chunks] : [];
2287
- }
2288
- async getAccumulatedContent(threadId) {
2289
- const buffer = this.getBufferIfValid(threadId);
2290
- if (!buffer) return "";
2291
- return buffer.chunks.map((chunk) => chunk.data?.content).join("");
2292
- }
2293
- async getChunksByMessageId(threadId, messageId) {
2294
- const buffer = this.getBufferIfValid(threadId);
2295
- if (!buffer) return [];
2296
- return buffer.chunks.filter((chunk) => chunk.data?.id === messageId);
2297
+ buffer.status = "active" /* ACTIVE */;
2297
2298
  }
2298
2299
  async completeThread(threadId) {
2299
2300
  const buffer = this.getBufferIfValid(threadId);
2300
2301
  if (buffer) {
2301
2302
  buffer.status = "completed" /* COMPLETED */;
2302
2303
  buffer.updatedAt = Date.now();
2304
+ buffer.chunks$.complete();
2303
2305
  }
2304
2306
  }
2305
2307
  async abortThread(threadId) {
@@ -2307,6 +2309,7 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2307
2309
  if (buffer) {
2308
2310
  buffer.status = "aborted" /* ABORTED */;
2309
2311
  buffer.updatedAt = Date.now();
2312
+ buffer.chunks$.error(new Error("Thread aborted"));
2310
2313
  }
2311
2314
  }
2312
2315
  async isThreadActive(threadId) {
@@ -2319,10 +2322,7 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2319
2322
  async getThreadBuffer(threadId) {
2320
2323
  const buffer = this.getBufferIfValid(threadId);
2321
2324
  if (!buffer) return void 0;
2322
- return {
2323
- ...buffer,
2324
- chunks: [...buffer.chunks]
2325
- };
2325
+ return buffer;
2326
2326
  }
2327
2327
  async clearThread(threadId) {
2328
2328
  this.buffers.delete(threadId);
@@ -2369,9 +2369,6 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2369
2369
  }
2370
2370
  return cleanedCount;
2371
2371
  }
2372
- /**
2373
- * Extend thread TTL
2374
- */
2375
2372
  async extendThreadTTL(threadId, additionalMs) {
2376
2373
  const buffer = this.getBufferIfValid(threadId);
2377
2374
  if (buffer) {
@@ -2380,62 +2377,69 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2380
2377
  buffer.updatedAt = Date.now();
2381
2378
  }
2382
2379
  }
2383
- /**
2384
- * Get new chunks since known content
2385
- * Used for resuming streams from a known position
2386
- * Matches the known content and returns chunks after that position
2387
- * Continues to yield new chunks as they are added until thread completes/aborts
2388
- */
2389
- async *getNewChunksSinceContent(threadId, messageId, knownContent) {
2390
- let buffer = this.getBufferIfValid(threadId);
2380
+ async *getNewChunksSinceContentIterator(threadId, messageId, knownContent) {
2381
+ const buffer = this.getBufferIfValid(threadId);
2391
2382
  if (!buffer) return;
2392
- let lastYieldedIndex = -1;
2393
2383
  let accumulatedContent = "";
2394
- for (let i = 0; i < buffer.chunks.length; i++) {
2395
- const chunk = buffer.chunks[i];
2396
- if (chunk.data?.id === messageId) {
2397
- accumulatedContent += chunk.data?.content || "";
2398
- if (accumulatedContent === knownContent) {
2399
- lastYieldedIndex = i;
2400
- break;
2384
+ const queue = [];
2385
+ let resolveNext = null;
2386
+ let errorNext = null;
2387
+ let isCompleted = false;
2388
+ const subscription = buffer.chunks$.subscribe({
2389
+ next: (chunk) => {
2390
+ queue.push(chunk);
2391
+ if (resolveNext) {
2392
+ const resolve = resolveNext;
2393
+ resolveNext = null;
2394
+ resolve();
2401
2395
  }
2402
- if (accumulatedContent.length > knownContent.length) {
2403
- if (accumulatedContent.startsWith(knownContent)) {
2404
- lastYieldedIndex = i;
2405
- break;
2406
- }
2396
+ },
2397
+ error: (err) => {
2398
+ if (errorNext) {
2399
+ const reject = errorNext;
2400
+ errorNext = null;
2401
+ reject(err);
2407
2402
  }
2408
- }
2409
- }
2410
- const pollingInterval = 100;
2411
- while (true) {
2412
- buffer = this.getBufferIfValid(threadId);
2413
- if (!buffer) break;
2414
- let hasNewChunks = false;
2415
- for (let i = lastYieldedIndex + 1; i < buffer.chunks.length; i++) {
2416
- const chunk = buffer.chunks[i];
2417
- if (chunk.data?.id === messageId) {
2418
- yield chunk;
2419
- lastYieldedIndex = i;
2420
- hasNewChunks = true;
2403
+ },
2404
+ complete: () => {
2405
+ isCompleted = true;
2406
+ if (resolveNext) {
2407
+ const resolve = resolveNext;
2408
+ resolveNext = null;
2409
+ resolve();
2421
2410
  }
2422
2411
  }
2423
- if (buffer.status === "completed" /* COMPLETED */ || buffer.status === "aborted" /* ABORTED */) {
2424
- break;
2425
- }
2426
- if (!hasNewChunks) {
2427
- await new Promise((resolve) => setTimeout(resolve, pollingInterval));
2412
+ });
2413
+ try {
2414
+ while (true) {
2415
+ if (queue.length === 0) {
2416
+ if (isCompleted) break;
2417
+ await new Promise((resolve, reject) => {
2418
+ resolveNext = resolve;
2419
+ errorNext = reject;
2420
+ });
2421
+ }
2422
+ while (queue.length > 0) {
2423
+ const chunk = queue.shift();
2424
+ if (!chunk) continue;
2425
+ if (chunk.data?.id === messageId) {
2426
+ accumulatedContent += chunk.data?.content || "";
2427
+ }
2428
+ if (accumulatedContent.length > knownContent.length) {
2429
+ if (accumulatedContent.startsWith(knownContent)) {
2430
+ yield chunk;
2431
+ }
2432
+ }
2433
+ }
2428
2434
  }
2435
+ } finally {
2436
+ subscription.unsubscribe();
2429
2437
  }
2430
2438
  }
2431
- /**
2432
- * Get statistics about the buffer
2433
- */
2434
2439
  getStats() {
2435
2440
  let activeCount = 0;
2436
2441
  let completedCount = 0;
2437
2442
  let abortedCount = 0;
2438
- let totalChunks = 0;
2439
2443
  const validBuffers = [];
2440
2444
  for (const [threadId, buffer] of this.buffers.entries()) {
2441
2445
  if (this.isExpired(buffer)) {
@@ -2445,7 +2449,6 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2445
2449
  }
2446
2450
  }
2447
2451
  for (const buffer of validBuffers) {
2448
- totalChunks += buffer.chunks.length;
2449
2452
  switch (buffer.status) {
2450
2453
  case "active" /* ACTIVE */:
2451
2454
  activeCount++;
@@ -2463,13 +2466,9 @@ var InMemoryChunkBuffer = class extends ChunkBuffer {
2463
2466
  activeThreads: activeCount,
2464
2467
  completedThreads: completedCount,
2465
2468
  abortedThreads: abortedCount,
2466
- totalChunks,
2467
2469
  config: this.config
2468
2470
  };
2469
2471
  }
2470
- /**
2471
- * Cleanup method for graceful shutdown
2472
- */
2473
2472
  dispose() {
2474
2473
  this.stopCleanupTimer();
2475
2474
  this.buffers.clear();