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.
- package/README.md +78 -10
- package/dist/{activities-CPIB2v2C.d.ts → activities-Bm4TLTid.d.ts} +24 -4
- package/dist/{activities-DnmNOnq4.d.cts → activities-CyeiqK_f.d.cts} +24 -4
- package/dist/adapters/sandbox/daytona/index.d.cts +2 -2
- package/dist/adapters/sandbox/daytona/index.d.ts +2 -2
- package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +1 -1
- package/dist/adapters/sandbox/e2b/index.d.ts +1 -1
- package/dist/adapters/thread/anthropic/index.cjs +171 -65
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +19 -4
- package/dist/adapters/thread/anthropic/index.d.ts +19 -4
- package/dist/adapters/thread/anthropic/index.js +171 -65
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +3 -1
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +4 -4
- package/dist/adapters/thread/anthropic/workflow.d.ts +4 -4
- package/dist/adapters/thread/anthropic/workflow.js +3 -1
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +171 -69
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -4
- package/dist/adapters/thread/google-genai/index.d.ts +5 -4
- package/dist/adapters/thread/google-genai/index.js +171 -69
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +3 -1
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -4
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -4
- package/dist/adapters/thread/google-genai/workflow.js +3 -1
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +181 -77
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +18 -4
- package/dist/adapters/thread/langchain/index.d.ts +18 -4
- package/dist/adapters/thread/langchain/index.js +182 -74
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +3 -1
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +4 -4
- package/dist/adapters/thread/langchain/workflow.d.ts +4 -4
- package/dist/adapters/thread/langchain/workflow.js +3 -1
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/cold-store-BC5L5Z8A.d.cts +117 -0
- package/dist/cold-store-CFHwemBJ.d.ts +117 -0
- package/dist/index.cjs +252 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +138 -8
- package/dist/index.d.ts +138 -8
- package/dist/index.js +247 -54
- package/dist/index.js.map +1 -1
- package/dist/{proxy-DTnc5rqT.d.cts → proxy-BxFyd6cg.d.cts} +1 -1
- package/dist/{proxy-B7Xi1znZ.d.ts → proxy-Cskmj4Yx.d.ts} +1 -1
- package/dist/{thread-manager-BlX2TwRN.d.cts → thread-manager-9tezUcLW.d.cts} +9 -3
- package/dist/{thread-manager-BAv340mi.d.ts → thread-manager-B-zy3xrs.d.ts} +9 -3
- package/dist/{thread-manager-D2xorI-J.d.ts → thread-manager-D33SUmZa.d.cts} +10 -4
- package/dist/{thread-manager-BWv6ZXI3.d.cts → thread-manager-DduoSkvJ.d.ts} +10 -4
- package/dist/{types-C90VoEpt.d.cts → types-CjY93AWZ.d.cts} +1 -1
- package/dist/{types-4Wmk-wRq.d.cts → types-CnuN9T6t.d.cts} +23 -1
- package/dist/{types-DKsCdAtQ.d.ts → types-CwN6_tAL.d.ts} +23 -1
- package/dist/{types-Clhqautb.d.ts → types-L5bvbF-n.d.ts} +17 -1
- package/dist/{types-DpFD8ofR.d.ts → types-gVa5XCWD.d.ts} +1 -1
- package/dist/{types-DRJt1TMi.d.cts → types-oxt8GN97.d.cts} +17 -1
- package/dist/{workflow-D32TRMr-.d.ts → workflow-B1TOcHbt.d.ts} +33 -2
- package/dist/{workflow-XVt0ww8K.d.cts → workflow-DIaIV7L2.d.cts} +33 -2
- package/dist/workflow.cjs +29 -19
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -2
- package/dist/workflow.d.ts +2 -2
- package/dist/workflow.js +29 -19
- package/dist/workflow.js.map +1 -1
- package/package.json +6 -1
- package/src/adapters/thread/anthropic/activities.ts +72 -36
- package/src/adapters/thread/anthropic/thread-manager.ts +9 -1
- package/src/adapters/thread/google-genai/activities.ts +64 -40
- package/src/adapters/thread/google-genai/thread-manager.ts +9 -1
- package/src/adapters/thread/langchain/activities.ts +63 -36
- package/src/adapters/thread/langchain/thread-manager.ts +9 -1
- package/src/index.ts +20 -1
- package/src/lib/session/session-edge-cases.integration.test.ts +12 -0
- package/src/lib/session/session.integration.test.ts +138 -0
- package/src/lib/session/session.ts +47 -22
- package/src/lib/session/types.ts +22 -0
- package/src/lib/thread/cold-store.test.ts +193 -0
- package/src/lib/thread/cold-store.ts +250 -0
- package/src/lib/thread/index.ts +32 -0
- package/src/lib/thread/keys.ts +20 -0
- package/src/lib/thread/manager.ts +16 -27
- package/src/lib/thread/proxy.ts +2 -0
- package/src/lib/thread/snapshot.test.ts +443 -0
- package/src/lib/thread/snapshot.ts +163 -0
- package/src/lib/thread/test-utils.ts +228 -0
- package/src/lib/thread/tiered.test.ts +281 -0
- package/src/lib/thread/tiered.ts +135 -0
- package/src/lib/thread/types.ts +16 -0
- package/src/lib/.env +0 -1
- package/src/tools/bash/.env +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zeitlich",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.46",
|
|
4
4
|
"description": "[EXPERIMENTAL] An opinionated AI agent implementation for Temporal",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -201,6 +201,7 @@
|
|
|
201
201
|
},
|
|
202
202
|
"devDependencies": {
|
|
203
203
|
"@anthropic-ai/sdk": "^0.93.0",
|
|
204
|
+
"@aws-sdk/client-s3": "^3.1000.0",
|
|
204
205
|
"@daytonaio/sdk": "^0.171.0",
|
|
205
206
|
"@e2b/code-interpreter": "^2.3.3",
|
|
206
207
|
"@eslint/js": "^10.0.1",
|
|
@@ -223,6 +224,7 @@
|
|
|
223
224
|
},
|
|
224
225
|
"peerDependencies": {
|
|
225
226
|
"@anthropic-ai/sdk": ">=0.50.0",
|
|
227
|
+
"@aws-sdk/client-s3": ">=3.700.0",
|
|
226
228
|
"@daytonaio/sdk": ">=0.153.0",
|
|
227
229
|
"@e2b/code-interpreter": "^2.3.3",
|
|
228
230
|
"@google/genai": "^1.43.0",
|
|
@@ -241,6 +243,9 @@
|
|
|
241
243
|
"@anthropic-ai/sdk": {
|
|
242
244
|
"optional": true
|
|
243
245
|
},
|
|
246
|
+
"@aws-sdk/client-s3": {
|
|
247
|
+
"optional": true
|
|
248
|
+
},
|
|
244
249
|
"@google/genai": {
|
|
245
250
|
"optional": true
|
|
246
251
|
},
|
|
@@ -13,11 +13,15 @@ import type {
|
|
|
13
13
|
ScopedPrefix,
|
|
14
14
|
} from "../../../lib/session/types";
|
|
15
15
|
import type { ModelInvoker } from "../../../lib/model";
|
|
16
|
+
import { createTieredThreadManager } from "../../../lib/thread/tiered";
|
|
17
|
+
import type { ColdThreadStore } from "../../../lib/thread/cold-store";
|
|
16
18
|
import {
|
|
17
19
|
createAnthropicThreadManager,
|
|
20
|
+
storedMessageId,
|
|
18
21
|
type AnthropicContent,
|
|
19
22
|
type AnthropicSystemContent,
|
|
20
23
|
type AnthropicThreadManagerHooks,
|
|
24
|
+
type StoredMessage,
|
|
21
25
|
} from "./thread-manager";
|
|
22
26
|
import {
|
|
23
27
|
createAnthropicModelInvoker,
|
|
@@ -38,6 +42,20 @@ export interface AnthropicAdapterConfig {
|
|
|
38
42
|
/** Maximum tokens to generate. Defaults to 16384. */
|
|
39
43
|
maxTokens?: number;
|
|
40
44
|
hooks?: AnthropicThreadManagerHooks;
|
|
45
|
+
/**
|
|
46
|
+
* Optional durable cold tier (e.g. S3, R2, GCS). When provided,
|
|
47
|
+
* the session will hydrate the thread from cold storage on entry
|
|
48
|
+
* (`continue`/`fork` modes) and flush it back on every exit path.
|
|
49
|
+
* When omitted, the adapter is Redis-only and `hydrateThread`/
|
|
50
|
+
* `flushThread` activities are no-ops.
|
|
51
|
+
*/
|
|
52
|
+
coldStore?: ColdThreadStore;
|
|
53
|
+
/**
|
|
54
|
+
* Override the default Redis TTL (90 days) for thread keys. When
|
|
55
|
+
* pairing the adapter with a `coldStore`, a shorter TTL (hours)
|
|
56
|
+
* is typically more appropriate.
|
|
57
|
+
*/
|
|
58
|
+
ttlSeconds?: number;
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
/**
|
|
@@ -135,16 +153,41 @@ export function createAnthropicAdapter(
|
|
|
135
153
|
): AnthropicAdapter {
|
|
136
154
|
const { redis, client } = config;
|
|
137
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Common per-call config plumbed into both the provider thread
|
|
158
|
+
* manager (for message I/O) and the tiered base manager (for
|
|
159
|
+
* hot↔cold lifecycle ops). Keeping them in lockstep means a single
|
|
160
|
+
* `coldStore` / `ttlSeconds` configuration controls every Redis
|
|
161
|
+
* write the adapter does.
|
|
162
|
+
*/
|
|
163
|
+
const baseExtras = {
|
|
164
|
+
...(config.ttlSeconds !== undefined && { ttlSeconds: config.ttlSeconds }),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const makeProviderThread = (threadId: string, threadKey?: string) =>
|
|
168
|
+
createAnthropicThreadManager({
|
|
169
|
+
redis,
|
|
170
|
+
threadId,
|
|
171
|
+
key: threadKey,
|
|
172
|
+
...baseExtras,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const makeTieredBase = (threadId: string, threadKey?: string) =>
|
|
176
|
+
createTieredThreadManager<StoredMessage>({
|
|
177
|
+
redis,
|
|
178
|
+
threadId,
|
|
179
|
+
key: threadKey,
|
|
180
|
+
idOf: storedMessageId,
|
|
181
|
+
...baseExtras,
|
|
182
|
+
...(config.coldStore && { coldStore: config.coldStore }),
|
|
183
|
+
});
|
|
184
|
+
|
|
138
185
|
const threadOps: ThreadOps<AnthropicContent> = {
|
|
139
186
|
async initializeThread(
|
|
140
187
|
threadId: string,
|
|
141
188
|
threadKey?: string
|
|
142
189
|
): Promise<void> {
|
|
143
|
-
const thread =
|
|
144
|
-
redis,
|
|
145
|
-
threadId,
|
|
146
|
-
key: threadKey,
|
|
147
|
-
});
|
|
190
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
148
191
|
await thread.initialize();
|
|
149
192
|
},
|
|
150
193
|
|
|
@@ -154,11 +197,7 @@ export function createAnthropicAdapter(
|
|
|
154
197
|
content: AnthropicContent,
|
|
155
198
|
threadKey?: string
|
|
156
199
|
): Promise<void> {
|
|
157
|
-
const thread =
|
|
158
|
-
redis,
|
|
159
|
-
threadId,
|
|
160
|
-
key: threadKey,
|
|
161
|
-
});
|
|
200
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
162
201
|
await thread.appendUserMessage(id, content);
|
|
163
202
|
},
|
|
164
203
|
|
|
@@ -168,21 +207,13 @@ export function createAnthropicAdapter(
|
|
|
168
207
|
content: AnthropicSystemContent,
|
|
169
208
|
threadKey?: string
|
|
170
209
|
): Promise<void> {
|
|
171
|
-
const thread =
|
|
172
|
-
redis,
|
|
173
|
-
threadId,
|
|
174
|
-
key: threadKey,
|
|
175
|
-
});
|
|
210
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
176
211
|
await thread.appendSystemMessage(id, content);
|
|
177
212
|
},
|
|
178
213
|
|
|
179
214
|
async appendToolResult(id: string, cfg: ToolResultConfig): Promise<void> {
|
|
180
215
|
const { threadId, threadKey, toolCallId, toolName, content } = cfg;
|
|
181
|
-
const thread =
|
|
182
|
-
redis,
|
|
183
|
-
threadId,
|
|
184
|
-
key: threadKey,
|
|
185
|
-
});
|
|
216
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
186
217
|
await thread.appendToolResult(id, toolCallId, toolName, content);
|
|
187
218
|
},
|
|
188
219
|
|
|
@@ -192,11 +223,7 @@ export function createAnthropicAdapter(
|
|
|
192
223
|
message: Anthropic.Messages.Message,
|
|
193
224
|
threadKey?: string
|
|
194
225
|
): Promise<void> {
|
|
195
|
-
const thread =
|
|
196
|
-
redis,
|
|
197
|
-
threadId,
|
|
198
|
-
key: threadKey,
|
|
199
|
-
});
|
|
226
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
200
227
|
await thread.appendAssistantMessage(id, message.content);
|
|
201
228
|
},
|
|
202
229
|
|
|
@@ -210,6 +237,7 @@ export function createAnthropicAdapter(
|
|
|
210
237
|
threadId: sourceThreadId,
|
|
211
238
|
key: threadKey,
|
|
212
239
|
hooks: config.hooks,
|
|
240
|
+
...baseExtras,
|
|
213
241
|
});
|
|
214
242
|
await thread.fork(targetThreadId);
|
|
215
243
|
},
|
|
@@ -219,7 +247,7 @@ export function createAnthropicAdapter(
|
|
|
219
247
|
messageId: string,
|
|
220
248
|
threadKey?: string,
|
|
221
249
|
): Promise<void> {
|
|
222
|
-
const thread =
|
|
250
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
223
251
|
await thread.truncateFromId(messageId);
|
|
224
252
|
},
|
|
225
253
|
|
|
@@ -227,11 +255,7 @@ export function createAnthropicAdapter(
|
|
|
227
255
|
threadId: string,
|
|
228
256
|
threadKey?: string
|
|
229
257
|
): Promise<PersistedThreadState | null> {
|
|
230
|
-
const thread =
|
|
231
|
-
redis,
|
|
232
|
-
threadId,
|
|
233
|
-
key: threadKey,
|
|
234
|
-
});
|
|
258
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
235
259
|
return thread.loadState();
|
|
236
260
|
},
|
|
237
261
|
|
|
@@ -240,13 +264,25 @@ export function createAnthropicAdapter(
|
|
|
240
264
|
state: PersistedThreadState,
|
|
241
265
|
threadKey?: string
|
|
242
266
|
): Promise<void> {
|
|
243
|
-
const thread =
|
|
244
|
-
redis,
|
|
245
|
-
threadId,
|
|
246
|
-
key: threadKey,
|
|
247
|
-
});
|
|
267
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
248
268
|
await thread.saveState(state);
|
|
249
269
|
},
|
|
270
|
+
|
|
271
|
+
async hydrateThread(
|
|
272
|
+
threadId: string,
|
|
273
|
+
threadKey?: string
|
|
274
|
+
): Promise<void> {
|
|
275
|
+
if (!config.coldStore) return;
|
|
276
|
+
await makeTieredBase(threadId, threadKey).hydrate();
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
async flushThread(
|
|
280
|
+
threadId: string,
|
|
281
|
+
threadKey?: string
|
|
282
|
+
): Promise<void> {
|
|
283
|
+
if (!config.coldStore) return;
|
|
284
|
+
await makeTieredBase(threadId, threadKey).flush();
|
|
285
|
+
},
|
|
250
286
|
};
|
|
251
287
|
|
|
252
288
|
function createActivities<S extends string = "">(
|
|
@@ -35,6 +35,12 @@ export interface AnthropicThreadManagerConfig {
|
|
|
35
35
|
/** Thread key, defaults to 'messages' */
|
|
36
36
|
key?: string;
|
|
37
37
|
hooks?: AnthropicThreadManagerHooks;
|
|
38
|
+
/**
|
|
39
|
+
* Override the default thread TTL (90 days). When pairing the
|
|
40
|
+
* adapter with a durable cold tier, a shorter TTL (hours) is
|
|
41
|
+
* typically more appropriate.
|
|
42
|
+
*/
|
|
43
|
+
ttlSeconds?: number;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
/** Prepared payload ready to send to the Anthropic API */
|
|
@@ -57,7 +63,8 @@ export interface AnthropicThreadManager extends ProviderThreadManager<
|
|
|
57
63
|
prepareForInvocation(): Promise<AnthropicInvocationPayload>;
|
|
58
64
|
}
|
|
59
65
|
|
|
60
|
-
|
|
66
|
+
/** Extract the unique id from a {@link StoredMessage}. */
|
|
67
|
+
export function storedMessageId(msg: StoredMessage): string {
|
|
61
68
|
return msg.id;
|
|
62
69
|
}
|
|
63
70
|
|
|
@@ -113,6 +120,7 @@ export function createAnthropicThreadManager(
|
|
|
113
120
|
threadId: config.threadId,
|
|
114
121
|
key: config.key,
|
|
115
122
|
idOf: storedMessageId,
|
|
123
|
+
...(config.ttlSeconds !== undefined && { ttlSeconds: config.ttlSeconds }),
|
|
116
124
|
};
|
|
117
125
|
|
|
118
126
|
const base = createThreadManager(baseConfig);
|
|
@@ -13,11 +13,15 @@ import type {
|
|
|
13
13
|
ScopedPrefix,
|
|
14
14
|
} from "../../../lib/session/types";
|
|
15
15
|
import type { ModelInvoker } from "../../../lib/model";
|
|
16
|
+
import { createTieredThreadManager } from "../../../lib/thread/tiered";
|
|
17
|
+
import type { ColdThreadStore } from "../../../lib/thread/cold-store";
|
|
16
18
|
import {
|
|
17
19
|
createGoogleGenAIThreadManager,
|
|
20
|
+
storedContentId,
|
|
18
21
|
type GoogleGenAIContent,
|
|
19
22
|
type GoogleGenAISystemContent,
|
|
20
23
|
type GoogleGenAIThreadManagerHooks,
|
|
24
|
+
type StoredContent,
|
|
21
25
|
} from "./thread-manager";
|
|
22
26
|
import { createGoogleGenAIModelInvoker } from "./model-invoker";
|
|
23
27
|
import { ADAPTER_ID } from "./adapter-id";
|
|
@@ -34,6 +38,19 @@ export interface GoogleGenAIAdapterConfig {
|
|
|
34
38
|
/** Default model name (e.g. 'gemini-2.5-flash'). If omitted, use `createModelInvoker()` */
|
|
35
39
|
model?: string;
|
|
36
40
|
hooks?: GoogleGenAIThreadManagerHooks;
|
|
41
|
+
/**
|
|
42
|
+
* Optional durable cold tier (e.g. S3, R2, GCS). When provided,
|
|
43
|
+
* the session hydrates the thread on entry (`continue`/`fork`) and
|
|
44
|
+
* flushes it on every exit path. When omitted, the adapter is
|
|
45
|
+
* Redis-only and `hydrateThread`/`flushThread` activities are no-ops.
|
|
46
|
+
*/
|
|
47
|
+
coldStore?: ColdThreadStore;
|
|
48
|
+
/**
|
|
49
|
+
* Override the default Redis TTL (90 days). When pairing the
|
|
50
|
+
* adapter with a `coldStore`, a shorter TTL (hours) is typically
|
|
51
|
+
* more appropriate.
|
|
52
|
+
*/
|
|
53
|
+
ttlSeconds?: number;
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
/**
|
|
@@ -140,16 +157,34 @@ export function createGoogleGenAIAdapter(
|
|
|
140
157
|
): GoogleGenAIAdapter {
|
|
141
158
|
const { redis } = config;
|
|
142
159
|
|
|
160
|
+
const baseExtras = {
|
|
161
|
+
...(config.ttlSeconds !== undefined && { ttlSeconds: config.ttlSeconds }),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const makeProviderThread = (threadId: string, threadKey?: string) =>
|
|
165
|
+
createGoogleGenAIThreadManager({
|
|
166
|
+
redis,
|
|
167
|
+
threadId,
|
|
168
|
+
key: threadKey,
|
|
169
|
+
...baseExtras,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const makeTieredBase = (threadId: string, threadKey?: string) =>
|
|
173
|
+
createTieredThreadManager<StoredContent>({
|
|
174
|
+
redis,
|
|
175
|
+
threadId,
|
|
176
|
+
key: threadKey,
|
|
177
|
+
idOf: storedContentId,
|
|
178
|
+
...baseExtras,
|
|
179
|
+
...(config.coldStore && { coldStore: config.coldStore }),
|
|
180
|
+
});
|
|
181
|
+
|
|
143
182
|
const threadOps: ThreadOps<GoogleGenAIContent> = {
|
|
144
183
|
async initializeThread(
|
|
145
184
|
threadId: string,
|
|
146
185
|
threadKey?: string
|
|
147
186
|
): Promise<void> {
|
|
148
|
-
const thread =
|
|
149
|
-
redis,
|
|
150
|
-
threadId,
|
|
151
|
-
key: threadKey,
|
|
152
|
-
});
|
|
187
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
153
188
|
await thread.initialize();
|
|
154
189
|
},
|
|
155
190
|
|
|
@@ -159,11 +194,7 @@ export function createGoogleGenAIAdapter(
|
|
|
159
194
|
content: GoogleGenAIContent,
|
|
160
195
|
threadKey?: string
|
|
161
196
|
): Promise<void> {
|
|
162
|
-
const thread =
|
|
163
|
-
redis,
|
|
164
|
-
threadId,
|
|
165
|
-
key: threadKey,
|
|
166
|
-
});
|
|
197
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
167
198
|
await thread.appendUserMessage(id, content);
|
|
168
199
|
},
|
|
169
200
|
|
|
@@ -173,21 +204,13 @@ export function createGoogleGenAIAdapter(
|
|
|
173
204
|
content: GoogleGenAISystemContent,
|
|
174
205
|
threadKey?: string
|
|
175
206
|
): Promise<void> {
|
|
176
|
-
const thread =
|
|
177
|
-
redis,
|
|
178
|
-
threadId,
|
|
179
|
-
key: threadKey,
|
|
180
|
-
});
|
|
207
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
181
208
|
await thread.appendSystemMessage(id, content);
|
|
182
209
|
},
|
|
183
210
|
|
|
184
211
|
async appendToolResult(id: string, cfg: ToolResultConfig): Promise<void> {
|
|
185
212
|
const { threadId, threadKey, toolCallId, toolName, content } = cfg;
|
|
186
|
-
const thread =
|
|
187
|
-
redis,
|
|
188
|
-
threadId,
|
|
189
|
-
key: threadKey,
|
|
190
|
-
});
|
|
213
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
191
214
|
await thread.appendToolResult(
|
|
192
215
|
id,
|
|
193
216
|
toolCallId,
|
|
@@ -202,11 +225,7 @@ export function createGoogleGenAIAdapter(
|
|
|
202
225
|
message: Content,
|
|
203
226
|
threadKey?: string
|
|
204
227
|
): Promise<void> {
|
|
205
|
-
const thread =
|
|
206
|
-
redis,
|
|
207
|
-
threadId,
|
|
208
|
-
key: threadKey,
|
|
209
|
-
});
|
|
228
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
210
229
|
await thread.appendModelContent(id, message.parts ?? []);
|
|
211
230
|
},
|
|
212
231
|
|
|
@@ -220,6 +239,7 @@ export function createGoogleGenAIAdapter(
|
|
|
220
239
|
threadId: sourceThreadId,
|
|
221
240
|
key: threadKey,
|
|
222
241
|
hooks: config.hooks,
|
|
242
|
+
...baseExtras,
|
|
223
243
|
});
|
|
224
244
|
await thread.fork(targetThreadId);
|
|
225
245
|
},
|
|
@@ -229,11 +249,7 @@ export function createGoogleGenAIAdapter(
|
|
|
229
249
|
messageId: string,
|
|
230
250
|
threadKey?: string,
|
|
231
251
|
): Promise<void> {
|
|
232
|
-
const thread =
|
|
233
|
-
redis,
|
|
234
|
-
threadId,
|
|
235
|
-
key: threadKey,
|
|
236
|
-
});
|
|
252
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
237
253
|
await thread.truncateFromId(messageId);
|
|
238
254
|
},
|
|
239
255
|
|
|
@@ -241,11 +257,7 @@ export function createGoogleGenAIAdapter(
|
|
|
241
257
|
threadId: string,
|
|
242
258
|
threadKey?: string
|
|
243
259
|
): Promise<PersistedThreadState | null> {
|
|
244
|
-
const thread =
|
|
245
|
-
redis,
|
|
246
|
-
threadId,
|
|
247
|
-
key: threadKey,
|
|
248
|
-
});
|
|
260
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
249
261
|
return thread.loadState();
|
|
250
262
|
},
|
|
251
263
|
|
|
@@ -254,13 +266,25 @@ export function createGoogleGenAIAdapter(
|
|
|
254
266
|
state: PersistedThreadState,
|
|
255
267
|
threadKey?: string
|
|
256
268
|
): Promise<void> {
|
|
257
|
-
const thread =
|
|
258
|
-
redis,
|
|
259
|
-
threadId,
|
|
260
|
-
key: threadKey,
|
|
261
|
-
});
|
|
269
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
262
270
|
await thread.saveState(state);
|
|
263
271
|
},
|
|
272
|
+
|
|
273
|
+
async hydrateThread(
|
|
274
|
+
threadId: string,
|
|
275
|
+
threadKey?: string
|
|
276
|
+
): Promise<void> {
|
|
277
|
+
if (!config.coldStore) return;
|
|
278
|
+
await makeTieredBase(threadId, threadKey).hydrate();
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
async flushThread(
|
|
282
|
+
threadId: string,
|
|
283
|
+
threadKey?: string
|
|
284
|
+
): Promise<void> {
|
|
285
|
+
if (!config.coldStore) return;
|
|
286
|
+
await makeTieredBase(threadId, threadKey).flush();
|
|
287
|
+
},
|
|
264
288
|
};
|
|
265
289
|
|
|
266
290
|
function createActivities<S extends string = "">(
|
|
@@ -31,6 +31,12 @@ export interface GoogleGenAIThreadManagerConfig {
|
|
|
31
31
|
/** Thread key, defaults to 'messages' */
|
|
32
32
|
key?: string;
|
|
33
33
|
hooks?: GoogleGenAIThreadManagerHooks;
|
|
34
|
+
/**
|
|
35
|
+
* Override the default thread TTL (90 days). When pairing the
|
|
36
|
+
* adapter with a durable cold tier, a shorter TTL (hours) is
|
|
37
|
+
* typically more appropriate.
|
|
38
|
+
*/
|
|
39
|
+
ttlSeconds?: number;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
/** Prepared payload ready to send to the Google GenAI API */
|
|
@@ -50,7 +56,8 @@ export interface GoogleGenAIThreadManager extends ProviderThreadManager<
|
|
|
50
56
|
prepareForInvocation(): Promise<GoogleGenAIInvocationPayload>;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
/** Extract the unique id from a {@link StoredContent}. */
|
|
60
|
+
export function storedContentId(msg: StoredContent): string {
|
|
54
61
|
return msg.id;
|
|
55
62
|
}
|
|
56
63
|
|
|
@@ -103,6 +110,7 @@ export function createGoogleGenAIThreadManager(
|
|
|
103
110
|
threadId: config.threadId,
|
|
104
111
|
key: config.key,
|
|
105
112
|
idOf: storedContentId,
|
|
113
|
+
...(config.ttlSeconds !== undefined && { ttlSeconds: config.ttlSeconds }),
|
|
106
114
|
};
|
|
107
115
|
|
|
108
116
|
const base = createThreadManager(baseConfig);
|
|
@@ -13,10 +13,13 @@ import type {
|
|
|
13
13
|
ScopedPrefix,
|
|
14
14
|
} from "../../../lib/session/types";
|
|
15
15
|
import type { ModelInvoker } from "../../../lib/model";
|
|
16
|
+
import { createTieredThreadManager } from "../../../lib/thread/tiered";
|
|
17
|
+
import type { ColdThreadStore } from "../../../lib/thread/cold-store";
|
|
16
18
|
import type { StoredMessage } from "@langchain/core/messages";
|
|
17
19
|
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
18
20
|
import {
|
|
19
21
|
createLangChainThreadManager,
|
|
22
|
+
storedMessageId,
|
|
20
23
|
type LangChainContent,
|
|
21
24
|
type LangChainSystemContent,
|
|
22
25
|
type LangChainThreadManagerHooks,
|
|
@@ -35,6 +38,19 @@ export interface LangChainAdapterConfig {
|
|
|
35
38
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
39
|
model?: BaseChatModel<any>;
|
|
37
40
|
hooks?: LangChainThreadManagerHooks;
|
|
41
|
+
/**
|
|
42
|
+
* Optional durable cold tier (e.g. S3, R2, GCS). When provided,
|
|
43
|
+
* the session hydrates the thread on entry (`continue`/`fork`) and
|
|
44
|
+
* flushes it on every exit path. When omitted, the adapter is
|
|
45
|
+
* Redis-only and `hydrateThread`/`flushThread` activities are no-ops.
|
|
46
|
+
*/
|
|
47
|
+
coldStore?: ColdThreadStore;
|
|
48
|
+
/**
|
|
49
|
+
* Override the default Redis TTL (90 days). When pairing the
|
|
50
|
+
* adapter with a `coldStore`, a shorter TTL (hours) is typically
|
|
51
|
+
* more appropriate.
|
|
52
|
+
*/
|
|
53
|
+
ttlSeconds?: number;
|
|
38
54
|
}
|
|
39
55
|
|
|
40
56
|
/**
|
|
@@ -117,16 +133,34 @@ export function createLangChainAdapter(
|
|
|
117
133
|
): LangChainAdapter {
|
|
118
134
|
const { redis } = config;
|
|
119
135
|
|
|
136
|
+
const baseExtras = {
|
|
137
|
+
...(config.ttlSeconds !== undefined && { ttlSeconds: config.ttlSeconds }),
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const makeProviderThread = (threadId: string, threadKey?: string) =>
|
|
141
|
+
createLangChainThreadManager({
|
|
142
|
+
redis,
|
|
143
|
+
threadId,
|
|
144
|
+
key: threadKey,
|
|
145
|
+
...baseExtras,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const makeTieredBase = (threadId: string, threadKey?: string) =>
|
|
149
|
+
createTieredThreadManager<StoredMessage>({
|
|
150
|
+
redis,
|
|
151
|
+
threadId,
|
|
152
|
+
key: threadKey,
|
|
153
|
+
idOf: storedMessageId,
|
|
154
|
+
...baseExtras,
|
|
155
|
+
...(config.coldStore && { coldStore: config.coldStore }),
|
|
156
|
+
});
|
|
157
|
+
|
|
120
158
|
const threadOps: ThreadOps<LangChainContent> = {
|
|
121
159
|
async initializeThread(
|
|
122
160
|
threadId: string,
|
|
123
161
|
threadKey?: string
|
|
124
162
|
): Promise<void> {
|
|
125
|
-
const thread =
|
|
126
|
-
redis,
|
|
127
|
-
threadId,
|
|
128
|
-
key: threadKey,
|
|
129
|
-
});
|
|
163
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
130
164
|
await thread.initialize();
|
|
131
165
|
},
|
|
132
166
|
|
|
@@ -136,11 +170,7 @@ export function createLangChainAdapter(
|
|
|
136
170
|
content: LangChainContent,
|
|
137
171
|
threadKey?: string
|
|
138
172
|
): Promise<void> {
|
|
139
|
-
const thread =
|
|
140
|
-
redis,
|
|
141
|
-
threadId,
|
|
142
|
-
key: threadKey,
|
|
143
|
-
});
|
|
173
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
144
174
|
await thread.appendUserMessage(id, content);
|
|
145
175
|
},
|
|
146
176
|
|
|
@@ -150,21 +180,13 @@ export function createLangChainAdapter(
|
|
|
150
180
|
content: LangChainSystemContent,
|
|
151
181
|
threadKey?: string
|
|
152
182
|
): Promise<void> {
|
|
153
|
-
const thread =
|
|
154
|
-
redis,
|
|
155
|
-
threadId,
|
|
156
|
-
key: threadKey,
|
|
157
|
-
});
|
|
183
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
158
184
|
await thread.appendSystemMessage(id, content);
|
|
159
185
|
},
|
|
160
186
|
|
|
161
187
|
async appendToolResult(id: string, cfg: ToolResultConfig): Promise<void> {
|
|
162
188
|
const { threadId, threadKey, toolCallId, content } = cfg;
|
|
163
|
-
const thread =
|
|
164
|
-
redis,
|
|
165
|
-
threadId,
|
|
166
|
-
key: threadKey,
|
|
167
|
-
});
|
|
189
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
168
190
|
await thread.appendToolResult(id, toolCallId, "", content);
|
|
169
191
|
},
|
|
170
192
|
|
|
@@ -174,11 +196,7 @@ export function createLangChainAdapter(
|
|
|
174
196
|
message: StoredMessage,
|
|
175
197
|
threadKey?: string
|
|
176
198
|
): Promise<void> {
|
|
177
|
-
const thread =
|
|
178
|
-
redis,
|
|
179
|
-
threadId,
|
|
180
|
-
key: threadKey,
|
|
181
|
-
});
|
|
199
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
182
200
|
const patched = { ...message, data: { ...message.data, id } };
|
|
183
201
|
await thread.append([patched]);
|
|
184
202
|
},
|
|
@@ -193,6 +211,7 @@ export function createLangChainAdapter(
|
|
|
193
211
|
threadId: sourceThreadId,
|
|
194
212
|
key: threadKey,
|
|
195
213
|
hooks: config.hooks,
|
|
214
|
+
...baseExtras,
|
|
196
215
|
});
|
|
197
216
|
await thread.fork(targetThreadId);
|
|
198
217
|
},
|
|
@@ -202,7 +221,7 @@ export function createLangChainAdapter(
|
|
|
202
221
|
messageId: string,
|
|
203
222
|
threadKey?: string,
|
|
204
223
|
): Promise<void> {
|
|
205
|
-
const thread =
|
|
224
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
206
225
|
await thread.truncateFromId(messageId);
|
|
207
226
|
},
|
|
208
227
|
|
|
@@ -210,11 +229,7 @@ export function createLangChainAdapter(
|
|
|
210
229
|
threadId: string,
|
|
211
230
|
threadKey?: string
|
|
212
231
|
): Promise<PersistedThreadState | null> {
|
|
213
|
-
const thread =
|
|
214
|
-
redis,
|
|
215
|
-
threadId,
|
|
216
|
-
key: threadKey,
|
|
217
|
-
});
|
|
232
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
218
233
|
return thread.loadState();
|
|
219
234
|
},
|
|
220
235
|
|
|
@@ -223,13 +238,25 @@ export function createLangChainAdapter(
|
|
|
223
238
|
state: PersistedThreadState,
|
|
224
239
|
threadKey?: string
|
|
225
240
|
): Promise<void> {
|
|
226
|
-
const thread =
|
|
227
|
-
redis,
|
|
228
|
-
threadId,
|
|
229
|
-
key: threadKey,
|
|
230
|
-
});
|
|
241
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
231
242
|
await thread.saveState(state);
|
|
232
243
|
},
|
|
244
|
+
|
|
245
|
+
async hydrateThread(
|
|
246
|
+
threadId: string,
|
|
247
|
+
threadKey?: string
|
|
248
|
+
): Promise<void> {
|
|
249
|
+
if (!config.coldStore) return;
|
|
250
|
+
await makeTieredBase(threadId, threadKey).hydrate();
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
async flushThread(
|
|
254
|
+
threadId: string,
|
|
255
|
+
threadKey?: string
|
|
256
|
+
): Promise<void> {
|
|
257
|
+
if (!config.coldStore) return;
|
|
258
|
+
await makeTieredBase(threadId, threadKey).flush();
|
|
259
|
+
},
|
|
233
260
|
};
|
|
234
261
|
|
|
235
262
|
function createActivities<S extends string = "">(
|
|
@@ -34,6 +34,12 @@ export interface LangChainThreadManagerConfig {
|
|
|
34
34
|
/** Thread key, defaults to 'messages' */
|
|
35
35
|
key?: string;
|
|
36
36
|
hooks?: LangChainThreadManagerHooks;
|
|
37
|
+
/**
|
|
38
|
+
* Override the default thread TTL (90 days). When pairing the
|
|
39
|
+
* adapter with a durable cold tier, a shorter TTL (hours) is
|
|
40
|
+
* typically more appropriate.
|
|
41
|
+
*/
|
|
42
|
+
ttlSeconds?: number;
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
/** Prepared payload ready to send to a LangChain chat model */
|
|
@@ -52,7 +58,8 @@ export interface LangChainThreadManager extends ProviderThreadManager<
|
|
|
52
58
|
prepareForInvocation(): Promise<LangChainInvocationPayload>;
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
/** Extract the unique id from a LangChain {@link StoredMessage}. */
|
|
62
|
+
export function storedMessageId(msg: StoredMessage): string {
|
|
56
63
|
if (msg.type === "tool" && msg.data.tool_call_id) {
|
|
57
64
|
return msg.data.tool_call_id;
|
|
58
65
|
}
|
|
@@ -77,6 +84,7 @@ export function createLangChainThreadManager(
|
|
|
77
84
|
threadId: config.threadId,
|
|
78
85
|
key: config.key,
|
|
79
86
|
idOf: storedMessageId,
|
|
87
|
+
...(config.ttlSeconds !== undefined && { ttlSeconds: config.ttlSeconds }),
|
|
80
88
|
};
|
|
81
89
|
|
|
82
90
|
const base = createThreadManager(baseConfig);
|