zeitlich 0.2.44 → 0.2.46

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 (99) hide show
  1. package/README.md +78 -10
  2. package/dist/{activities-CPIB2v2C.d.ts → activities-Bm4TLTid.d.ts} +24 -4
  3. package/dist/{activities-DnmNOnq4.d.cts → activities-CyeiqK_f.d.cts} +24 -4
  4. package/dist/adapters/sandbox/daytona/index.d.cts +2 -2
  5. package/dist/adapters/sandbox/daytona/index.d.ts +2 -2
  6. package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
  7. package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
  8. package/dist/adapters/sandbox/e2b/index.d.cts +1 -1
  9. package/dist/adapters/sandbox/e2b/index.d.ts +1 -1
  10. package/dist/adapters/thread/anthropic/index.cjs +171 -65
  11. package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
  12. package/dist/adapters/thread/anthropic/index.d.cts +19 -4
  13. package/dist/adapters/thread/anthropic/index.d.ts +19 -4
  14. package/dist/adapters/thread/anthropic/index.js +171 -65
  15. package/dist/adapters/thread/anthropic/index.js.map +1 -1
  16. package/dist/adapters/thread/anthropic/workflow.cjs +3 -1
  17. package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
  18. package/dist/adapters/thread/anthropic/workflow.d.cts +4 -4
  19. package/dist/adapters/thread/anthropic/workflow.d.ts +4 -4
  20. package/dist/adapters/thread/anthropic/workflow.js +3 -1
  21. package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
  22. package/dist/adapters/thread/google-genai/index.cjs +171 -69
  23. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  24. package/dist/adapters/thread/google-genai/index.d.cts +5 -4
  25. package/dist/adapters/thread/google-genai/index.d.ts +5 -4
  26. package/dist/adapters/thread/google-genai/index.js +171 -69
  27. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  28. package/dist/adapters/thread/google-genai/workflow.cjs +3 -1
  29. package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
  30. package/dist/adapters/thread/google-genai/workflow.d.cts +5 -4
  31. package/dist/adapters/thread/google-genai/workflow.d.ts +5 -4
  32. package/dist/adapters/thread/google-genai/workflow.js +3 -1
  33. package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
  34. package/dist/adapters/thread/langchain/index.cjs +181 -77
  35. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  36. package/dist/adapters/thread/langchain/index.d.cts +18 -4
  37. package/dist/adapters/thread/langchain/index.d.ts +18 -4
  38. package/dist/adapters/thread/langchain/index.js +182 -74
  39. package/dist/adapters/thread/langchain/index.js.map +1 -1
  40. package/dist/adapters/thread/langchain/workflow.cjs +3 -1
  41. package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
  42. package/dist/adapters/thread/langchain/workflow.d.cts +4 -4
  43. package/dist/adapters/thread/langchain/workflow.d.ts +4 -4
  44. package/dist/adapters/thread/langchain/workflow.js +3 -1
  45. package/dist/adapters/thread/langchain/workflow.js.map +1 -1
  46. package/dist/cold-store-BC5L5Z8A.d.cts +117 -0
  47. package/dist/cold-store-CFHwemBJ.d.ts +117 -0
  48. package/dist/index.cjs +252 -53
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +138 -8
  51. package/dist/index.d.ts +138 -8
  52. package/dist/index.js +247 -54
  53. package/dist/index.js.map +1 -1
  54. package/dist/{proxy-DTnc5rqT.d.cts → proxy-BxFyd6cg.d.cts} +1 -1
  55. package/dist/{proxy-B7Xi1znZ.d.ts → proxy-Cskmj4Yx.d.ts} +1 -1
  56. package/dist/{thread-manager-BlX2TwRN.d.cts → thread-manager-9tezUcLW.d.cts} +9 -3
  57. package/dist/{thread-manager-BAv340mi.d.ts → thread-manager-B-zy3xrs.d.ts} +9 -3
  58. package/dist/{thread-manager-D2xorI-J.d.ts → thread-manager-D33SUmZa.d.cts} +10 -4
  59. package/dist/{thread-manager-BWv6ZXI3.d.cts → thread-manager-DduoSkvJ.d.ts} +10 -4
  60. package/dist/{types-C90VoEpt.d.cts → types-CjY93AWZ.d.cts} +1 -1
  61. package/dist/{types-4Wmk-wRq.d.cts → types-CnuN9T6t.d.cts} +23 -1
  62. package/dist/{types-DKsCdAtQ.d.ts → types-CwN6_tAL.d.ts} +23 -1
  63. package/dist/{types-Clhqautb.d.ts → types-L5bvbF-n.d.ts} +17 -1
  64. package/dist/{types-DpFD8ofR.d.ts → types-gVa5XCWD.d.ts} +1 -1
  65. package/dist/{types-DRJt1TMi.d.cts → types-oxt8GN97.d.cts} +17 -1
  66. package/dist/{workflow-D32TRMr-.d.ts → workflow-B1TOcHbt.d.ts} +33 -2
  67. package/dist/{workflow-XVt0ww8K.d.cts → workflow-DIaIV7L2.d.cts} +33 -2
  68. package/dist/workflow.cjs +29 -19
  69. package/dist/workflow.cjs.map +1 -1
  70. package/dist/workflow.d.cts +2 -2
  71. package/dist/workflow.d.ts +2 -2
  72. package/dist/workflow.js +29 -19
  73. package/dist/workflow.js.map +1 -1
  74. package/package.json +6 -1
  75. package/src/adapters/thread/anthropic/activities.ts +72 -36
  76. package/src/adapters/thread/anthropic/thread-manager.ts +9 -1
  77. package/src/adapters/thread/google-genai/activities.ts +64 -40
  78. package/src/adapters/thread/google-genai/thread-manager.ts +9 -1
  79. package/src/adapters/thread/langchain/activities.ts +63 -36
  80. package/src/adapters/thread/langchain/thread-manager.ts +9 -1
  81. package/src/index.ts +20 -1
  82. package/src/lib/session/session-edge-cases.integration.test.ts +12 -0
  83. package/src/lib/session/session.integration.test.ts +138 -0
  84. package/src/lib/session/session.ts +47 -22
  85. package/src/lib/session/types.ts +22 -0
  86. package/src/lib/thread/cold-store.test.ts +193 -0
  87. package/src/lib/thread/cold-store.ts +250 -0
  88. package/src/lib/thread/index.ts +32 -0
  89. package/src/lib/thread/keys.ts +20 -0
  90. package/src/lib/thread/manager.ts +16 -27
  91. package/src/lib/thread/proxy.ts +2 -0
  92. package/src/lib/thread/snapshot.test.ts +443 -0
  93. package/src/lib/thread/snapshot.ts +163 -0
  94. package/src/lib/thread/test-utils.ts +228 -0
  95. package/src/lib/thread/tiered.test.ts +281 -0
  96. package/src/lib/thread/tiered.ts +135 -0
  97. package/src/lib/thread/types.ts +16 -0
  98. package/src/lib/.env +0 -1
  99. package/src/tools/bash/.env +0 -1
package/dist/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { defineSignal, CancellationScope, isCancellation, uuid4, setHandler, defineUpdate, ApplicationFailure, log, defineQuery, condition, proxySinks, workflowInfo, proxyActivities, getExternalWorkflowHandle, executeChild } from '@temporalio/workflow';
2
2
  import z14, { z } from 'zod';
3
- import crypto from 'crypto';
3
+ import { randomUUID, randomFillSync } from 'crypto';
4
4
  import { ApplicationFailure as ApplicationFailure$1 } from '@temporalio/common';
5
5
  import { join, resolve, posix } from 'path';
6
+ import { gzipSync, gunzipSync } from 'zlib';
7
+ import { DeleteObjectCommand, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
6
8
  import { Context } from '@temporalio/activity';
7
9
  import { promises } from 'fs';
8
10
 
@@ -1032,7 +1034,9 @@ async function createSession(config) {
1032
1034
  appendAgentMessage,
1033
1035
  forkThread,
1034
1036
  loadThreadState,
1035
- saveThreadState
1037
+ saveThreadState,
1038
+ hydrateThread,
1039
+ flushThread
1036
1040
  } = threadOps;
1037
1041
  const plugins = [];
1038
1042
  let destroySubagentSandboxes;
@@ -1092,10 +1096,7 @@ async function createSession(config) {
1092
1096
  stateManager.run();
1093
1097
  }
1094
1098
  );
1095
- const lifecycle = resolveSessionLifecycle(
1096
- sandboxInit,
1097
- sandboxShutdown
1098
- );
1099
+ const lifecycle = resolveSessionLifecycle(sandboxInit, sandboxShutdown);
1099
1100
  const sandboxMode = lifecycle.mode;
1100
1101
  const resolvedShutdown = lifecycle.shutdown;
1101
1102
  let sandboxId;
@@ -1170,20 +1171,6 @@ async function createSession(config) {
1170
1171
  ...baseSnapshot && { baseSnapshot }
1171
1172
  });
1172
1173
  }
1173
- if (hooks.onSessionStart) {
1174
- await hooks.onSessionStart({
1175
- threadId,
1176
- agentName,
1177
- metadata
1178
- });
1179
- }
1180
- log.info("session started", {
1181
- agentName,
1182
- threadId,
1183
- threadMode,
1184
- maxTurns,
1185
- ...sandboxId && { sandboxId }
1186
- });
1187
1174
  const sessionStartMs = Date.now();
1188
1175
  const systemPrompt = stateManager.getSystemPrompt();
1189
1176
  const rehydrateFromSlice = (slice) => {
@@ -1193,10 +1180,12 @@ async function createSession(config) {
1193
1180
  });
1194
1181
  };
1195
1182
  if (threadMode === "fork" && sourceThreadId) {
1183
+ await hydrateThread(sourceThreadId, threadKey);
1196
1184
  await forkThread(sourceThreadId, threadId, threadKey);
1197
1185
  const forkedSlice = await loadThreadState(threadId, threadKey);
1198
1186
  if (forkedSlice) rehydrateFromSlice(forkedSlice);
1199
1187
  } else if (threadMode === "continue") {
1188
+ await hydrateThread(threadId, threadKey);
1200
1189
  const continuedSlice = await loadThreadState(threadId, threadKey);
1201
1190
  if (continuedSlice) rehydrateFromSlice(continuedSlice);
1202
1191
  } else {
@@ -1256,6 +1245,20 @@ async function createSession(config) {
1256
1245
  );
1257
1246
  let exitReason = "completed";
1258
1247
  let finalMessage = null;
1248
+ if (hooks.onSessionStart) {
1249
+ await hooks.onSessionStart({
1250
+ threadId,
1251
+ agentName,
1252
+ metadata
1253
+ });
1254
+ }
1255
+ log.info("session started", {
1256
+ agentName,
1257
+ threadId,
1258
+ threadMode,
1259
+ maxTurns,
1260
+ ...sandboxId && { sandboxId }
1261
+ });
1259
1262
  try {
1260
1263
  let assistantId;
1261
1264
  while (stateManager.isRunning() && !stateManager.isTerminal() && stateManager.getTurns() < maxTurns) {
@@ -1364,6 +1367,15 @@ async function createSession(config) {
1364
1367
  error: persistError instanceof Error ? persistError.message : String(persistError)
1365
1368
  });
1366
1369
  }
1370
+ try {
1371
+ await flushThread(threadId, threadKey);
1372
+ } catch (flushError) {
1373
+ log.warn("failed to flush thread to cold tier", {
1374
+ agentName,
1375
+ threadId,
1376
+ error: flushError instanceof Error ? flushError.message : String(flushError)
1377
+ });
1378
+ }
1367
1379
  await callSessionEnd(exitReason, stateManager.getTurns());
1368
1380
  if (sandboxOwned && sandboxId && sandboxOps) {
1369
1381
  switch (resolvedShutdown) {
@@ -1447,6 +1459,9 @@ function getThreadMetaKey(threadKey, threadId) {
1447
1459
  function getThreadStateKey(threadKey, threadId) {
1448
1460
  return `${threadKey}:state:thread:${threadId}`;
1449
1461
  }
1462
+ function getThreadDedupKey(threadId, dedupId) {
1463
+ return `dedup:${dedupId}:thread:${threadId}`;
1464
+ }
1450
1465
 
1451
1466
  // src/lib/types.ts
1452
1467
  function isTerminalStatus(status) {
@@ -1653,7 +1668,7 @@ function createAgentStateManager({
1653
1668
  };
1654
1669
  }
1655
1670
 
1656
- // ../2_monorepo/node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/stringify.js
1671
+ // node_modules/uuid/dist/esm/stringify.js
1657
1672
  var byteToHex = [];
1658
1673
  for (let i = 0; i < 256; ++i) {
1659
1674
  byteToHex.push((i + 256).toString(16).slice(1));
@@ -1665,26 +1680,30 @@ var rnds8Pool = new Uint8Array(256);
1665
1680
  var poolPtr = rnds8Pool.length;
1666
1681
  function rng() {
1667
1682
  if (poolPtr > rnds8Pool.length - 16) {
1668
- crypto.randomFillSync(rnds8Pool);
1683
+ randomFillSync(rnds8Pool);
1669
1684
  poolPtr = 0;
1670
1685
  }
1671
1686
  return rnds8Pool.slice(poolPtr, poolPtr += 16);
1672
1687
  }
1673
- var native_default = {
1674
- randomUUID: crypto.randomUUID
1675
- };
1688
+ var native_default = { randomUUID };
1676
1689
 
1677
- // ../2_monorepo/node_modules/.pnpm/uuid@10.0.0/node_modules/uuid/dist/esm-node/v4.js
1690
+ // node_modules/uuid/dist/esm/v4.js
1678
1691
  function v4(options, buf, offset) {
1679
1692
  if (native_default.randomUUID && !buf && !options) {
1680
1693
  return native_default.randomUUID();
1681
1694
  }
1682
1695
  options = options || {};
1683
- const rnds = options.random || (options.rng || rng)();
1696
+ const rnds = options.random ?? options.rng?.() ?? rng();
1697
+ if (rnds.length < 16) {
1698
+ throw new Error("Random bytes length must be >= 16");
1699
+ }
1684
1700
  rnds[6] = rnds[6] & 15 | 64;
1685
1701
  rnds[8] = rnds[8] & 63 | 128;
1686
1702
  if (buf) {
1687
1703
  offset = offset || 0;
1704
+ if (offset < 0 || offset + 16 > buf.length) {
1705
+ throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
1706
+ }
1688
1707
  for (let i = 0; i < 16; ++i) {
1689
1708
  buf[offset + i] = rnds[i];
1690
1709
  }
@@ -2587,9 +2606,6 @@ redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
2587
2606
  redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
2588
2607
  return 1
2589
2608
  `;
2590
- function getDedupKey(threadId, id) {
2591
- return `dedup:${id}:thread:${threadId}`;
2592
- }
2593
2609
  function createThreadManager(config) {
2594
2610
  const {
2595
2611
  redis,
@@ -2597,11 +2613,13 @@ function createThreadManager(config) {
2597
2613
  key = "messages",
2598
2614
  serialize = (m) => JSON.stringify(m),
2599
2615
  deserialize = (raw) => JSON.parse(raw),
2600
- idOf
2616
+ idOf,
2617
+ ttlSeconds = THREAD_TTL_SECONDS
2601
2618
  } = config;
2602
2619
  const redisKey = getThreadListKey(key, threadId);
2603
2620
  const metaKey = getThreadMetaKey(key, threadId);
2604
2621
  const stateKey = getThreadStateKey(key, threadId);
2622
+ const dedupKey = (id) => getThreadDedupKey(threadId, id);
2605
2623
  async function assertThreadExists() {
2606
2624
  const exists = await redis.exists(metaKey);
2607
2625
  if (!exists) {
@@ -2611,7 +2629,7 @@ function createThreadManager(config) {
2611
2629
  return {
2612
2630
  async initialize() {
2613
2631
  await redis.del(redisKey);
2614
- await redis.set(metaKey, "1", "EX", THREAD_TTL_SECONDS);
2632
+ await redis.set(metaKey, "1", "EX", ttlSeconds);
2615
2633
  },
2616
2634
  async load() {
2617
2635
  await assertThreadExists();
@@ -2623,18 +2641,17 @@ function createThreadManager(config) {
2623
2641
  await assertThreadExists();
2624
2642
  if (idOf) {
2625
2643
  const dedupId = messages.map(idOf).join(":");
2626
- const dedupKey = getDedupKey(threadId, dedupId);
2627
2644
  await redis.eval(
2628
2645
  APPEND_IDEMPOTENT_SCRIPT,
2629
2646
  2,
2630
- dedupKey,
2647
+ dedupKey(dedupId),
2631
2648
  redisKey,
2632
- String(THREAD_TTL_SECONDS),
2649
+ String(ttlSeconds),
2633
2650
  ...messages.map(serialize)
2634
2651
  );
2635
2652
  } else {
2636
2653
  await redis.rpush(redisKey, ...messages.map(serialize));
2637
- await redis.expire(redisKey, THREAD_TTL_SECONDS);
2654
+ await redis.expire(redisKey, ttlSeconds);
2638
2655
  }
2639
2656
  },
2640
2657
  async fork(newThreadId) {
@@ -2649,11 +2666,11 @@ function createThreadManager(config) {
2649
2666
  if (data.length > 0) {
2650
2667
  const newKey = getThreadListKey(key, newThreadId);
2651
2668
  await redis.rpush(newKey, ...data);
2652
- await redis.expire(newKey, THREAD_TTL_SECONDS);
2669
+ await redis.expire(newKey, ttlSeconds);
2653
2670
  }
2654
2671
  if (stateRaw != null) {
2655
2672
  const newStateKey = getThreadStateKey(key, newThreadId);
2656
- await redis.set(newStateKey, stateRaw, "EX", THREAD_TTL_SECONDS);
2673
+ await redis.set(newStateKey, stateRaw, "EX", ttlSeconds);
2657
2674
  }
2658
2675
  return forked;
2659
2676
  },
@@ -2668,15 +2685,13 @@ function createThreadManager(config) {
2668
2685
  const existingIds = existing.map((raw) => idOf(deserialize(raw))).filter((id) => typeof id === "string");
2669
2686
  await redis.del(redisKey);
2670
2687
  if (existingIds.length > 0) {
2671
- await redis.del(
2672
- ...existingIds.map((id) => getDedupKey(threadId, id))
2673
- );
2688
+ await redis.del(...existingIds.map(dedupKey));
2674
2689
  }
2675
2690
  if (messages.length > 0) {
2676
2691
  await redis.rpush(redisKey, ...messages.map(serialize));
2677
- await redis.expire(redisKey, THREAD_TTL_SECONDS);
2692
+ await redis.expire(redisKey, ttlSeconds);
2678
2693
  }
2679
- await redis.expire(metaKey, THREAD_TTL_SECONDS);
2694
+ await redis.expire(metaKey, ttlSeconds);
2680
2695
  },
2681
2696
  async delete() {
2682
2697
  await redis.del(redisKey, metaKey, stateKey);
@@ -2688,12 +2703,7 @@ function createThreadManager(config) {
2688
2703
  },
2689
2704
  async saveState(state) {
2690
2705
  await assertThreadExists();
2691
- await redis.set(
2692
- stateKey,
2693
- JSON.stringify(state),
2694
- "EX",
2695
- THREAD_TTL_SECONDS
2696
- );
2706
+ await redis.set(stateKey, JSON.stringify(state), "EX", ttlSeconds);
2697
2707
  },
2698
2708
  async deleteState() {
2699
2709
  await redis.del(stateKey);
@@ -2722,19 +2732,202 @@ function createThreadManager(config) {
2722
2732
  if (idx === -1) return;
2723
2733
  if (idx === 0) {
2724
2734
  await redis.del(redisKey);
2725
- await redis.expire(metaKey, THREAD_TTL_SECONDS);
2735
+ await redis.expire(metaKey, ttlSeconds);
2726
2736
  } else {
2727
2737
  await redis.ltrim(redisKey, 0, idx - 1);
2728
- await redis.expire(redisKey, THREAD_TTL_SECONDS);
2738
+ await redis.expire(redisKey, ttlSeconds);
2729
2739
  }
2730
2740
  if (removedIds.length > 0) {
2731
- await redis.del(
2732
- ...removedIds.map((id) => getDedupKey(threadId, id))
2741
+ await redis.del(...removedIds.map(dedupKey));
2742
+ }
2743
+ }
2744
+ };
2745
+ }
2746
+ function joinKey(parts) {
2747
+ return parts.map((p) => p.replace(/^\/+|\/+$/g, "")).filter((p) => p.length > 0).join("/");
2748
+ }
2749
+ function buildKey(prefix, threadKey, threadId, gzip) {
2750
+ const ext = gzip ? "json.gz" : "json";
2751
+ return joinKey([
2752
+ prefix ?? "threads",
2753
+ threadKey,
2754
+ `${threadId}.${ext}`
2755
+ ]);
2756
+ }
2757
+ async function streamToBuffer(body) {
2758
+ if (body == null) return Buffer.alloc(0);
2759
+ if (body instanceof Uint8Array) return Buffer.from(body);
2760
+ if (typeof body.transformToByteArray === "function") {
2761
+ const bytes = await body.transformToByteArray();
2762
+ return Buffer.from(bytes);
2763
+ }
2764
+ if (typeof body.arrayBuffer === "function") {
2765
+ const ab = await body.arrayBuffer();
2766
+ return Buffer.from(ab);
2767
+ }
2768
+ const chunks = [];
2769
+ for await (const chunk of body) {
2770
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
2771
+ }
2772
+ return Buffer.concat(chunks);
2773
+ }
2774
+ function createS3ColdStore(config) {
2775
+ const { s3, bucket, prefix, gzip = true } = config;
2776
+ const contentType = config.contentType ?? (gzip ? "application/gzip" : "application/json");
2777
+ return {
2778
+ async read(threadKey, threadId) {
2779
+ const Key = buildKey(prefix, threadKey, threadId, gzip);
2780
+ try {
2781
+ const resp = await s3.send(
2782
+ new GetObjectCommand({ Bucket: bucket, Key })
2733
2783
  );
2784
+ const buf = await streamToBuffer(resp.Body);
2785
+ const json = gzip ? gunzipSync(buf).toString("utf8") : buf.toString("utf8");
2786
+ return JSON.parse(json);
2787
+ } catch (err) {
2788
+ if (isNotFound(err)) return null;
2789
+ throw err;
2734
2790
  }
2791
+ },
2792
+ async write(threadKey, threadId, snapshot) {
2793
+ const Key = buildKey(prefix, threadKey, threadId, gzip);
2794
+ const json = JSON.stringify(snapshot);
2795
+ const body = gzip ? gzipSync(Buffer.from(json, "utf8")) : json;
2796
+ await s3.send(
2797
+ new PutObjectCommand({
2798
+ Bucket: bucket,
2799
+ Key,
2800
+ Body: body,
2801
+ ContentType: contentType
2802
+ })
2803
+ );
2804
+ },
2805
+ async delete(threadKey, threadId) {
2806
+ const Key = buildKey(prefix, threadKey, threadId, gzip);
2807
+ await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key }));
2735
2808
  }
2736
2809
  };
2737
2810
  }
2811
+ function isNotFound(err) {
2812
+ if (typeof err !== "object" || err === null) return false;
2813
+ const e = err;
2814
+ return e.name === "NoSuchKey" || e.Code === "NoSuchKey" || e.code === "NoSuchKey" || e.name === "NotFound" || e.$metadata?.httpStatusCode === 404;
2815
+ }
2816
+
2817
+ // src/lib/thread/snapshot.ts
2818
+ async function encodeSnapshot(config) {
2819
+ const { redis, threadKey, threadId, idOf } = config;
2820
+ const metaKey = getThreadMetaKey(threadKey, threadId);
2821
+ if (await redis.exists(metaKey) === 0) {
2822
+ return null;
2823
+ }
2824
+ const listKey = getThreadListKey(threadKey, threadId);
2825
+ const stateKey = getThreadStateKey(threadKey, threadId);
2826
+ const messages = await redis.lrange(listKey, 0, -1);
2827
+ const stateRaw = await redis.get(stateKey);
2828
+ const state = stateRaw == null ? null : JSON.parse(stateRaw);
2829
+ const dedupIds = idOf ? messages.map(idOf) : [];
2830
+ return { v: 1, messages, state, dedupIds };
2831
+ }
2832
+ async function applySnapshot(config) {
2833
+ const {
2834
+ redis,
2835
+ threadKey,
2836
+ threadId,
2837
+ snapshot,
2838
+ ttlSeconds = THREAD_TTL_SECONDS
2839
+ } = config;
2840
+ const metaKey = getThreadMetaKey(threadKey, threadId);
2841
+ if (await redis.exists(metaKey) === 1) {
2842
+ return;
2843
+ }
2844
+ const listKey = getThreadListKey(threadKey, threadId);
2845
+ const stateKey = getThreadStateKey(threadKey, threadId);
2846
+ await redis.del(listKey, stateKey);
2847
+ const pipeline = redis.pipeline();
2848
+ if (snapshot.messages.length > 0) {
2849
+ pipeline.rpush(listKey, ...snapshot.messages);
2850
+ pipeline.expire(listKey, ttlSeconds);
2851
+ }
2852
+ if (snapshot.state != null) {
2853
+ pipeline.set(stateKey, JSON.stringify(snapshot.state), "EX", ttlSeconds);
2854
+ }
2855
+ for (const id of snapshot.dedupIds) {
2856
+ pipeline.set(getThreadDedupKey(threadId, id), "1", "EX", ttlSeconds);
2857
+ }
2858
+ const results = await pipeline.exec();
2859
+ if (results) {
2860
+ const firstErr = results.find(([err]) => err)?.[0] ?? null;
2861
+ if (firstErr) {
2862
+ await redis.del(
2863
+ listKey,
2864
+ stateKey,
2865
+ ...snapshot.dedupIds.map((id) => getThreadDedupKey(threadId, id))
2866
+ ).catch(() => void 0);
2867
+ throw firstErr;
2868
+ }
2869
+ }
2870
+ await redis.set(metaKey, "1", "EX", ttlSeconds);
2871
+ }
2872
+ async function clearHotTier(config) {
2873
+ const { redis, threadKey, threadId, dedupIds = [] } = config;
2874
+ const keys = [
2875
+ getThreadListKey(threadKey, threadId),
2876
+ getThreadMetaKey(threadKey, threadId),
2877
+ getThreadStateKey(threadKey, threadId),
2878
+ ...dedupIds.map((id) => getThreadDedupKey(threadId, id))
2879
+ ];
2880
+ await redis.del(...keys);
2881
+ }
2882
+
2883
+ // src/lib/thread/tiered.ts
2884
+ function createTieredThreadManager(config) {
2885
+ const {
2886
+ redis,
2887
+ threadId,
2888
+ key = "messages",
2889
+ coldStore,
2890
+ idOf,
2891
+ deserialize = (raw) => JSON.parse(raw),
2892
+ ttlSeconds = THREAD_TTL_SECONDS
2893
+ } = config;
2894
+ const base = createThreadManager(config);
2895
+ const rawIdOf = idOf ? (raw) => idOf(deserialize(raw)) : void 0;
2896
+ return Object.assign(base, {
2897
+ async hydrate() {
2898
+ if (!coldStore) return;
2899
+ const snapshot = await coldStore.read(key, threadId);
2900
+ if (!snapshot) return;
2901
+ await applySnapshot({
2902
+ redis,
2903
+ threadKey: key,
2904
+ threadId,
2905
+ snapshot,
2906
+ ttlSeconds
2907
+ });
2908
+ },
2909
+ async flush(opts) {
2910
+ if (!coldStore) return;
2911
+ const snapshot = await encodeSnapshot({
2912
+ redis,
2913
+ threadKey: key,
2914
+ threadId,
2915
+ ...rawIdOf ? { idOf: rawIdOf } : {}
2916
+ });
2917
+ if (!snapshot) return;
2918
+ await coldStore.write(key, threadId, snapshot);
2919
+ const deleteHot = opts?.deleteHot ?? true;
2920
+ if (deleteHot) {
2921
+ await clearHotTier({
2922
+ redis,
2923
+ threadKey: key,
2924
+ threadId,
2925
+ dedupIds: snapshot.dedupIds
2926
+ });
2927
+ }
2928
+ }
2929
+ });
2930
+ }
2738
2931
  function getActivityContext() {
2739
2932
  try {
2740
2933
  const ctx = Context.current();
@@ -3670,6 +3863,6 @@ var toTree = async (fs, opts = {}) => {
3670
3863
  return base + subtree;
3671
3864
  };
3672
3865
 
3673
- export { DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT, FileSystemSkillProvider, NodeFsSandboxFileSystem, SandboxManager, SandboxNotFoundError, SandboxNotSupportedError, THREAD_TTL_SECONDS, VirtualFileSystem, applyVirtualTreeMutations, askUserQuestionTool, bashHandler, bashTool, composeHooks, createAgentStateManager, createAskUserQuestionHandler, createBashToolDescription, createObservabilityHooks, createReadSkillHandler, createReadSkillTool, createRunAgentActivity, createSession, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createToolRouter, createVirtualFsActivities, defineSubagent, defineSubagentWorkflow, defineTool, defineWorkflow, editHandler, editTool, filesWithMimeType, formatVirtualFileTree, getActivityContext, getShortId, getThreadListKey, getThreadMetaKey, globHandler, globTool, grepTool, hasDirectory, hasFileWithMimeType, hasNoOtherToolCalls, isTerminalStatus, parseSkillFile, proxyRunAgent, proxyVirtualFsOps, queryParentWorkflowState, readFileHandler, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, withParentWorkflowState, withSandbox, withVirtualFs, writeFileHandler, writeFileTool };
3866
+ export { DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT, FileSystemSkillProvider, NodeFsSandboxFileSystem, SandboxManager, SandboxNotFoundError, SandboxNotSupportedError, THREAD_TTL_SECONDS, VirtualFileSystem, applySnapshot, applyVirtualTreeMutations, askUserQuestionTool, bashHandler, bashTool, clearHotTier, composeHooks, createAgentStateManager, createAskUserQuestionHandler, createBashToolDescription, createObservabilityHooks, createReadSkillHandler, createReadSkillTool, createRunAgentActivity, createS3ColdStore, createSession, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createTieredThreadManager, createToolRouter, createVirtualFsActivities, defineSubagent, defineSubagentWorkflow, defineTool, defineWorkflow, editHandler, editTool, encodeSnapshot, filesWithMimeType, formatVirtualFileTree, getActivityContext, getShortId, getThreadDedupKey, getThreadListKey, getThreadMetaKey, getThreadStateKey, globHandler, globTool, grepTool, hasDirectory, hasFileWithMimeType, hasNoOtherToolCalls, isTerminalStatus, parseSkillFile, proxyRunAgent, proxyVirtualFsOps, queryParentWorkflowState, readFileHandler, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, withParentWorkflowState, withSandbox, withVirtualFs, writeFileHandler, writeFileTool };
3674
3867
  //# sourceMappingURL=index.js.map
3675
3868
  //# sourceMappingURL=index.js.map