zeitlich 0.2.45 → 0.2.47
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 +137 -11
- package/dist/{activities-Coafq5zr.d.cts → activities-CPwKoUlD.d.cts} +22 -2
- package/dist/{activities-CrN-ghLo.d.ts → activities-DlaBxNID.d.ts} +22 -2
- package/dist/adapters/thread/anthropic/index.cjs +276 -71
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +62 -8
- package/dist/adapters/thread/anthropic/index.d.ts +62 -8
- package/dist/adapters/thread/anthropic/index.js +275 -72
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +38 -20
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -4
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -4
- package/dist/adapters/thread/anthropic/workflow.js +38 -20
- 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 +6 -4
- package/dist/adapters/thread/google-genai/index.d.ts +6 -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 +38 -20
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +7 -4
- package/dist/adapters/thread/google-genai/workflow.d.ts +7 -4
- package/dist/adapters/thread/google-genai/workflow.js +38 -20
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +170 -66
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +19 -4
- package/dist/adapters/thread/langchain/index.d.ts +19 -4
- package/dist/adapters/thread/langchain/index.js +170 -66
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +38 -20
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -4
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -4
- package/dist/adapters/thread/langchain/workflow.js +38 -20
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/cold-store-BDgJpwLI.d.ts +114 -0
- package/dist/cold-store-Z2wvK2cV.d.cts +114 -0
- package/dist/index.cjs +440 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +150 -8
- package/dist/index.d.ts +150 -8
- package/dist/index.js +432 -68
- package/dist/index.js.map +1 -1
- package/dist/proxy-CDh3Rsa7.d.cts +40 -0
- package/dist/proxy-Du8ggERu.d.ts +40 -0
- package/dist/{thread-manager-wRVVBFgj.d.cts → thread-manager-BjoYYXgd.d.cts} +8 -2
- package/dist/{thread-manager-BsLO3Fgc.d.cts → thread-manager-D8zKNFZ9.d.cts} +8 -2
- package/dist/{thread-manager-Bi1XlbpJ.d.ts → thread-manager-DtHYws2F.d.ts} +8 -2
- package/dist/{thread-manager-BhkOyQ1I.d.ts → thread-manager-Dw96FKH1.d.ts} +8 -2
- package/dist/{types-C66-BVBr.d.cts → types-BMJrsHo0.d.cts} +17 -1
- package/dist/{types-BkX4HLzi.d.ts → types-CtdOquo3.d.ts} +17 -1
- package/dist/{types-CdALEF3z.d.cts → types-DNEl5uxQ.d.cts} +38 -0
- package/dist/{types-ChAy_jSP.d.ts → types-qQVZfhoT.d.ts} +38 -0
- package/dist/{workflow-DMmiaw6w.d.cts → workflow-BH9ImDGq.d.cts} +48 -2
- package/dist/{workflow-BwT5EybR.d.ts → workflow-Cdw3-RNB.d.ts} +48 -2
- package/dist/workflow.cjs +47 -4
- 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 +47 -5
- package/dist/workflow.js.map +1 -1
- package/package.json +14 -3
- package/src/adapters/thread/anthropic/activities.ts +82 -39
- package/src/adapters/thread/anthropic/index.ts +8 -0
- package/src/adapters/thread/anthropic/model-invoker.test.ts +110 -0
- package/src/adapters/thread/anthropic/model-invoker.ts +26 -5
- package/src/adapters/thread/anthropic/prompt-cache.test.ts +134 -0
- package/src/adapters/thread/anthropic/prompt-cache.ts +163 -0
- package/src/adapters/thread/anthropic/proxy.ts +1 -0
- 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/proxy.ts +1 -0
- 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/proxy.ts +1 -0
- package/src/adapters/thread/langchain/thread-manager.ts +9 -1
- package/src/index.ts +21 -2
- 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 +29 -0
- package/src/lib/session/types.ts +22 -0
- package/src/lib/subagent/define.ts +1 -0
- package/src/lib/subagent/handler.ts +11 -2
- package/src/lib/subagent/subagent.integration.test.ts +139 -0
- package/src/lib/subagent/types.ts +16 -0
- package/src/lib/thread/cold-store.test.ts +221 -0
- package/src/lib/thread/cold-store.ts +269 -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 +79 -27
- 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/tools/edit/handler.test.ts +177 -0
- package/src/tools/edit/handler.ts +249 -47
- package/src/tools/edit/tool.ts +40 -0
- package/src/tools/task-create/handler.ts +1 -1
- package/src/tools/task-update/handler.ts +1 -1
- package/src/workflow.ts +2 -2
- package/dist/proxy-Bf7uI-Hw.d.cts +0 -24
- package/dist/proxy-COqA95FW.d.ts +0 -24
|
@@ -14,6 +14,9 @@ function getThreadMetaKey(threadKey, threadId) {
|
|
|
14
14
|
function getThreadStateKey(threadKey, threadId) {
|
|
15
15
|
return `${threadKey}:state:thread:${threadId}`;
|
|
16
16
|
}
|
|
17
|
+
function getThreadDedupKey(threadId, dedupId) {
|
|
18
|
+
return `dedup:${dedupId}:thread:${threadId}`;
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
// src/lib/thread/manager.ts
|
|
19
22
|
var APPEND_IDEMPOTENT_SCRIPT = `
|
|
@@ -27,9 +30,6 @@ redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
|
|
|
27
30
|
redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
|
|
28
31
|
return 1
|
|
29
32
|
`;
|
|
30
|
-
function getDedupKey(threadId, id) {
|
|
31
|
-
return `dedup:${id}:thread:${threadId}`;
|
|
32
|
-
}
|
|
33
33
|
function createThreadManager(config) {
|
|
34
34
|
const {
|
|
35
35
|
redis,
|
|
@@ -37,11 +37,13 @@ function createThreadManager(config) {
|
|
|
37
37
|
key = "messages",
|
|
38
38
|
serialize = (m) => JSON.stringify(m),
|
|
39
39
|
deserialize = (raw) => JSON.parse(raw),
|
|
40
|
-
idOf
|
|
40
|
+
idOf,
|
|
41
|
+
ttlSeconds = THREAD_TTL_SECONDS
|
|
41
42
|
} = config;
|
|
42
43
|
const redisKey = getThreadListKey(key, threadId);
|
|
43
44
|
const metaKey = getThreadMetaKey(key, threadId);
|
|
44
45
|
const stateKey = getThreadStateKey(key, threadId);
|
|
46
|
+
const dedupKey = (id) => getThreadDedupKey(threadId, id);
|
|
45
47
|
async function assertThreadExists() {
|
|
46
48
|
const exists = await redis.exists(metaKey);
|
|
47
49
|
if (!exists) {
|
|
@@ -51,7 +53,7 @@ function createThreadManager(config) {
|
|
|
51
53
|
return {
|
|
52
54
|
async initialize() {
|
|
53
55
|
await redis.del(redisKey);
|
|
54
|
-
await redis.set(metaKey, "1", "EX",
|
|
56
|
+
await redis.set(metaKey, "1", "EX", ttlSeconds);
|
|
55
57
|
},
|
|
56
58
|
async load() {
|
|
57
59
|
await assertThreadExists();
|
|
@@ -63,18 +65,17 @@ function createThreadManager(config) {
|
|
|
63
65
|
await assertThreadExists();
|
|
64
66
|
if (idOf) {
|
|
65
67
|
const dedupId = messages.map(idOf).join(":");
|
|
66
|
-
const dedupKey = getDedupKey(threadId, dedupId);
|
|
67
68
|
await redis.eval(
|
|
68
69
|
APPEND_IDEMPOTENT_SCRIPT,
|
|
69
70
|
2,
|
|
70
|
-
dedupKey,
|
|
71
|
+
dedupKey(dedupId),
|
|
71
72
|
redisKey,
|
|
72
|
-
String(
|
|
73
|
+
String(ttlSeconds),
|
|
73
74
|
...messages.map(serialize)
|
|
74
75
|
);
|
|
75
76
|
} else {
|
|
76
77
|
await redis.rpush(redisKey, ...messages.map(serialize));
|
|
77
|
-
await redis.expire(redisKey,
|
|
78
|
+
await redis.expire(redisKey, ttlSeconds);
|
|
78
79
|
}
|
|
79
80
|
},
|
|
80
81
|
async fork(newThreadId) {
|
|
@@ -89,11 +90,11 @@ function createThreadManager(config) {
|
|
|
89
90
|
if (data.length > 0) {
|
|
90
91
|
const newKey = getThreadListKey(key, newThreadId);
|
|
91
92
|
await redis.rpush(newKey, ...data);
|
|
92
|
-
await redis.expire(newKey,
|
|
93
|
+
await redis.expire(newKey, ttlSeconds);
|
|
93
94
|
}
|
|
94
95
|
if (stateRaw != null) {
|
|
95
96
|
const newStateKey = getThreadStateKey(key, newThreadId);
|
|
96
|
-
await redis.set(newStateKey, stateRaw, "EX",
|
|
97
|
+
await redis.set(newStateKey, stateRaw, "EX", ttlSeconds);
|
|
97
98
|
}
|
|
98
99
|
return forked;
|
|
99
100
|
},
|
|
@@ -108,15 +109,13 @@ function createThreadManager(config) {
|
|
|
108
109
|
const existingIds = existing.map((raw) => idOf(deserialize(raw))).filter((id) => typeof id === "string");
|
|
109
110
|
await redis.del(redisKey);
|
|
110
111
|
if (existingIds.length > 0) {
|
|
111
|
-
await redis.del(
|
|
112
|
-
...existingIds.map((id) => getDedupKey(threadId, id))
|
|
113
|
-
);
|
|
112
|
+
await redis.del(...existingIds.map(dedupKey));
|
|
114
113
|
}
|
|
115
114
|
if (messages.length > 0) {
|
|
116
115
|
await redis.rpush(redisKey, ...messages.map(serialize));
|
|
117
|
-
await redis.expire(redisKey,
|
|
116
|
+
await redis.expire(redisKey, ttlSeconds);
|
|
118
117
|
}
|
|
119
|
-
await redis.expire(metaKey,
|
|
118
|
+
await redis.expire(metaKey, ttlSeconds);
|
|
120
119
|
},
|
|
121
120
|
async delete() {
|
|
122
121
|
await redis.del(redisKey, metaKey, stateKey);
|
|
@@ -128,12 +127,7 @@ function createThreadManager(config) {
|
|
|
128
127
|
},
|
|
129
128
|
async saveState(state) {
|
|
130
129
|
await assertThreadExists();
|
|
131
|
-
await redis.set(
|
|
132
|
-
stateKey,
|
|
133
|
-
JSON.stringify(state),
|
|
134
|
-
"EX",
|
|
135
|
-
THREAD_TTL_SECONDS
|
|
136
|
-
);
|
|
130
|
+
await redis.set(stateKey, JSON.stringify(state), "EX", ttlSeconds);
|
|
137
131
|
},
|
|
138
132
|
async deleteState() {
|
|
139
133
|
await redis.del(stateKey);
|
|
@@ -162,20 +156,133 @@ function createThreadManager(config) {
|
|
|
162
156
|
if (idx === -1) return;
|
|
163
157
|
if (idx === 0) {
|
|
164
158
|
await redis.del(redisKey);
|
|
165
|
-
await redis.expire(metaKey,
|
|
159
|
+
await redis.expire(metaKey, ttlSeconds);
|
|
166
160
|
} else {
|
|
167
161
|
await redis.ltrim(redisKey, 0, idx - 1);
|
|
168
|
-
await redis.expire(redisKey,
|
|
162
|
+
await redis.expire(redisKey, ttlSeconds);
|
|
169
163
|
}
|
|
170
164
|
if (removedIds.length > 0) {
|
|
171
|
-
await redis.del(
|
|
172
|
-
...removedIds.map((id) => getDedupKey(threadId, id))
|
|
173
|
-
);
|
|
165
|
+
await redis.del(...removedIds.map(dedupKey));
|
|
174
166
|
}
|
|
175
167
|
}
|
|
176
168
|
};
|
|
177
169
|
}
|
|
178
170
|
|
|
171
|
+
// src/lib/thread/snapshot.ts
|
|
172
|
+
async function encodeSnapshot(config) {
|
|
173
|
+
const { redis, threadKey, threadId, idOf } = config;
|
|
174
|
+
const metaKey = getThreadMetaKey(threadKey, threadId);
|
|
175
|
+
if (await redis.exists(metaKey) === 0) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const listKey = getThreadListKey(threadKey, threadId);
|
|
179
|
+
const stateKey = getThreadStateKey(threadKey, threadId);
|
|
180
|
+
const messages = await redis.lrange(listKey, 0, -1);
|
|
181
|
+
const stateRaw = await redis.get(stateKey);
|
|
182
|
+
const state = stateRaw == null ? null : JSON.parse(stateRaw);
|
|
183
|
+
const dedupIds = idOf ? messages.map(idOf) : [];
|
|
184
|
+
return { v: 1, messages, state, dedupIds };
|
|
185
|
+
}
|
|
186
|
+
async function applySnapshot(config) {
|
|
187
|
+
const {
|
|
188
|
+
redis,
|
|
189
|
+
threadKey,
|
|
190
|
+
threadId,
|
|
191
|
+
snapshot,
|
|
192
|
+
ttlSeconds = THREAD_TTL_SECONDS
|
|
193
|
+
} = config;
|
|
194
|
+
const metaKey = getThreadMetaKey(threadKey, threadId);
|
|
195
|
+
if (await redis.exists(metaKey) === 1) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const listKey = getThreadListKey(threadKey, threadId);
|
|
199
|
+
const stateKey = getThreadStateKey(threadKey, threadId);
|
|
200
|
+
await redis.del(listKey, stateKey);
|
|
201
|
+
const pipeline = redis.pipeline();
|
|
202
|
+
if (snapshot.messages.length > 0) {
|
|
203
|
+
pipeline.rpush(listKey, ...snapshot.messages);
|
|
204
|
+
pipeline.expire(listKey, ttlSeconds);
|
|
205
|
+
}
|
|
206
|
+
if (snapshot.state != null) {
|
|
207
|
+
pipeline.set(stateKey, JSON.stringify(snapshot.state), "EX", ttlSeconds);
|
|
208
|
+
}
|
|
209
|
+
for (const id of snapshot.dedupIds) {
|
|
210
|
+
pipeline.set(getThreadDedupKey(threadId, id), "1", "EX", ttlSeconds);
|
|
211
|
+
}
|
|
212
|
+
const results = await pipeline.exec();
|
|
213
|
+
if (results) {
|
|
214
|
+
const firstErr = results.find(([err]) => err)?.[0] ?? null;
|
|
215
|
+
if (firstErr) {
|
|
216
|
+
await redis.del(
|
|
217
|
+
listKey,
|
|
218
|
+
stateKey,
|
|
219
|
+
...snapshot.dedupIds.map((id) => getThreadDedupKey(threadId, id))
|
|
220
|
+
).catch(() => void 0);
|
|
221
|
+
throw firstErr;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
await redis.set(metaKey, "1", "EX", ttlSeconds);
|
|
225
|
+
}
|
|
226
|
+
async function clearHotTier(config) {
|
|
227
|
+
const { redis, threadKey, threadId, dedupIds = [] } = config;
|
|
228
|
+
const keys = [
|
|
229
|
+
getThreadListKey(threadKey, threadId),
|
|
230
|
+
getThreadMetaKey(threadKey, threadId),
|
|
231
|
+
getThreadStateKey(threadKey, threadId),
|
|
232
|
+
...dedupIds.map((id) => getThreadDedupKey(threadId, id))
|
|
233
|
+
];
|
|
234
|
+
await redis.del(...keys);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/lib/thread/tiered.ts
|
|
238
|
+
function createTieredThreadManager(config) {
|
|
239
|
+
const {
|
|
240
|
+
redis,
|
|
241
|
+
threadId,
|
|
242
|
+
key = "messages",
|
|
243
|
+
coldStore,
|
|
244
|
+
idOf,
|
|
245
|
+
deserialize = (raw) => JSON.parse(raw),
|
|
246
|
+
ttlSeconds = THREAD_TTL_SECONDS
|
|
247
|
+
} = config;
|
|
248
|
+
const base = createThreadManager(config);
|
|
249
|
+
const rawIdOf = idOf ? (raw) => idOf(deserialize(raw)) : void 0;
|
|
250
|
+
return Object.assign(base, {
|
|
251
|
+
async hydrate() {
|
|
252
|
+
if (!coldStore) return;
|
|
253
|
+
const snapshot = await coldStore.read(key, threadId);
|
|
254
|
+
if (!snapshot) return;
|
|
255
|
+
await applySnapshot({
|
|
256
|
+
redis,
|
|
257
|
+
threadKey: key,
|
|
258
|
+
threadId,
|
|
259
|
+
snapshot,
|
|
260
|
+
ttlSeconds
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
async flush(opts) {
|
|
264
|
+
if (!coldStore) return;
|
|
265
|
+
const snapshot = await encodeSnapshot({
|
|
266
|
+
redis,
|
|
267
|
+
threadKey: key,
|
|
268
|
+
threadId,
|
|
269
|
+
...rawIdOf ? { idOf: rawIdOf } : {}
|
|
270
|
+
});
|
|
271
|
+
if (!snapshot) return;
|
|
272
|
+
await coldStore.write(key, threadId, snapshot);
|
|
273
|
+
const deleteHot = opts?.deleteHot ?? true;
|
|
274
|
+
if (deleteHot) {
|
|
275
|
+
await clearHotTier({
|
|
276
|
+
redis,
|
|
277
|
+
threadKey: key,
|
|
278
|
+
threadId,
|
|
279
|
+
dedupIds: snapshot.dedupIds
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
179
286
|
// src/adapters/thread/anthropic/thread-manager.ts
|
|
180
287
|
function storedMessageId(msg) {
|
|
181
288
|
return msg.id;
|
|
@@ -208,7 +315,8 @@ function createAnthropicThreadManager(config) {
|
|
|
208
315
|
redis: config.redis,
|
|
209
316
|
threadId: config.threadId,
|
|
210
317
|
key: config.key,
|
|
211
|
-
idOf: storedMessageId
|
|
318
|
+
idOf: storedMessageId,
|
|
319
|
+
...config.ttlSeconds !== void 0 && { ttlSeconds: config.ttlSeconds }
|
|
212
320
|
};
|
|
213
321
|
const base = createThreadManager(baseConfig);
|
|
214
322
|
const helpers = {
|
|
@@ -308,6 +416,94 @@ function createAnthropicThreadManager(config) {
|
|
|
308
416
|
};
|
|
309
417
|
return manager;
|
|
310
418
|
}
|
|
419
|
+
|
|
420
|
+
// src/adapters/thread/anthropic/prompt-cache.ts
|
|
421
|
+
var DEFAULT_MAX_CACHE_BREAKPOINTS = 4;
|
|
422
|
+
var UNCACHEABLE_BLOCK_TYPES = /* @__PURE__ */ new Set(["thinking", "redacted_thinking"]);
|
|
423
|
+
function resolvePromptCacheOptions(promptCache) {
|
|
424
|
+
if (promptCache === false) return void 0;
|
|
425
|
+
if (promptCache === true || promptCache === void 0) return {};
|
|
426
|
+
return promptCache;
|
|
427
|
+
}
|
|
428
|
+
function addPromptCacheControl(payload, options = {}) {
|
|
429
|
+
const maxBreakpoints = options.maxBreakpoints ?? DEFAULT_MAX_CACHE_BREAKPOINTS;
|
|
430
|
+
if (maxBreakpoints <= 0) return payload;
|
|
431
|
+
if (countCacheControls(payload) >= maxBreakpoints) return payload;
|
|
432
|
+
const cacheControl = {
|
|
433
|
+
type: "ephemeral",
|
|
434
|
+
ttl: options.ttl ?? "5m"
|
|
435
|
+
};
|
|
436
|
+
const messages = addCacheControlToLastMessageBlock(
|
|
437
|
+
payload.messages,
|
|
438
|
+
cacheControl
|
|
439
|
+
);
|
|
440
|
+
if (messages === payload.messages) return payload;
|
|
441
|
+
return { ...payload, messages };
|
|
442
|
+
}
|
|
443
|
+
function addCacheControlToLastMessageBlock(messages, cacheControl) {
|
|
444
|
+
for (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex--) {
|
|
445
|
+
const message = messages[messageIndex];
|
|
446
|
+
if (!message) continue;
|
|
447
|
+
if (typeof message.content === "string") {
|
|
448
|
+
if (message.content.length === 0) continue;
|
|
449
|
+
return replaceMessage(messages, messageIndex, {
|
|
450
|
+
...message,
|
|
451
|
+
content: [
|
|
452
|
+
{ type: "text", text: message.content, cache_control: cacheControl }
|
|
453
|
+
]
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
if (!Array.isArray(message.content)) continue;
|
|
457
|
+
for (let blockIndex = message.content.length - 1; blockIndex >= 0; blockIndex--) {
|
|
458
|
+
const block = message.content[blockIndex];
|
|
459
|
+
if (!isCacheableContentBlock(block)) continue;
|
|
460
|
+
if (hasCacheControl(block)) return messages;
|
|
461
|
+
const content = [...message.content];
|
|
462
|
+
content[blockIndex] = {
|
|
463
|
+
...block,
|
|
464
|
+
cache_control: cacheControl
|
|
465
|
+
};
|
|
466
|
+
return replaceMessage(messages, messageIndex, { ...message, content });
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return messages;
|
|
470
|
+
}
|
|
471
|
+
function replaceMessage(messages, index, message) {
|
|
472
|
+
const next = [...messages];
|
|
473
|
+
next[index] = message;
|
|
474
|
+
return next;
|
|
475
|
+
}
|
|
476
|
+
function isCacheableContentBlock(block) {
|
|
477
|
+
if (!isRecord(block)) return false;
|
|
478
|
+
const type = typeof block.type === "string" ? block.type : void 0;
|
|
479
|
+
if (type && UNCACHEABLE_BLOCK_TYPES.has(type)) return false;
|
|
480
|
+
if (type === "text" && block.text === "") return false;
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
function countCacheControls(payload) {
|
|
484
|
+
let count = 0;
|
|
485
|
+
for (const tool of payload.tools ?? []) {
|
|
486
|
+
if (hasCacheControl(tool)) count++;
|
|
487
|
+
}
|
|
488
|
+
if (Array.isArray(payload.system)) {
|
|
489
|
+
for (const block of payload.system) {
|
|
490
|
+
if (hasCacheControl(block)) count++;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
for (const message of payload.messages) {
|
|
494
|
+
if (!Array.isArray(message.content)) continue;
|
|
495
|
+
for (const block of message.content) {
|
|
496
|
+
if (hasCacheControl(block)) count++;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return count;
|
|
500
|
+
}
|
|
501
|
+
function hasCacheControl(value) {
|
|
502
|
+
return isRecord(value) && value.cache_control != null;
|
|
503
|
+
}
|
|
504
|
+
function isRecord(value) {
|
|
505
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
506
|
+
}
|
|
311
507
|
function getActivityContext() {
|
|
312
508
|
try {
|
|
313
509
|
const ctx = Context.current();
|
|
@@ -330,6 +526,7 @@ function createAnthropicModelInvoker({
|
|
|
330
526
|
client,
|
|
331
527
|
model,
|
|
332
528
|
maxTokens = 16384,
|
|
529
|
+
promptCache,
|
|
333
530
|
hooks
|
|
334
531
|
}) {
|
|
335
532
|
return async function invokeAnthropicModel2(config) {
|
|
@@ -342,15 +539,20 @@ function createAnthropicModelInvoker({
|
|
|
342
539
|
hooks
|
|
343
540
|
});
|
|
344
541
|
await thread.truncateFromId(assistantMessageId);
|
|
345
|
-
const
|
|
542
|
+
const prepared = await thread.prepareForInvocation();
|
|
346
543
|
const anthropicTools = toAnthropicTools(state.tools);
|
|
347
|
-
const
|
|
544
|
+
const preparedPayload = {
|
|
545
|
+
...prepared,
|
|
546
|
+
...anthropicTools.length > 0 ? { tools: anthropicTools } : {}
|
|
547
|
+
};
|
|
548
|
+
const cacheOptions = resolvePromptCacheOptions(promptCache);
|
|
549
|
+
const payload = cacheOptions ? addPromptCacheControl(preparedPayload, cacheOptions) : preparedPayload;
|
|
348
550
|
const params = {
|
|
349
551
|
model,
|
|
350
552
|
max_tokens: maxTokens,
|
|
351
|
-
messages,
|
|
352
|
-
...system ? { system } : {},
|
|
353
|
-
...tools ? { tools } : {}
|
|
553
|
+
messages: payload.messages,
|
|
554
|
+
...payload.system ? { system: payload.system } : {},
|
|
555
|
+
...payload.tools ? { tools: payload.tools } : {}
|
|
354
556
|
};
|
|
355
557
|
const stream = client.messages.stream(params, { signal });
|
|
356
558
|
for await (const _event of stream) {
|
|
@@ -381,6 +583,7 @@ async function invokeAnthropicModel({
|
|
|
381
583
|
client,
|
|
382
584
|
model,
|
|
383
585
|
maxTokens,
|
|
586
|
+
promptCache,
|
|
384
587
|
hooks,
|
|
385
588
|
config
|
|
386
589
|
}) {
|
|
@@ -389,6 +592,7 @@ async function invokeAnthropicModel({
|
|
|
389
592
|
client,
|
|
390
593
|
model,
|
|
391
594
|
maxTokens,
|
|
595
|
+
promptCache,
|
|
392
596
|
hooks
|
|
393
597
|
});
|
|
394
598
|
return invoker(config);
|
|
@@ -397,46 +601,43 @@ async function invokeAnthropicModel({
|
|
|
397
601
|
// src/adapters/thread/anthropic/activities.ts
|
|
398
602
|
function createAnthropicAdapter(config) {
|
|
399
603
|
const { redis, client } = config;
|
|
604
|
+
const baseExtras = {
|
|
605
|
+
...config.ttlSeconds !== void 0 && { ttlSeconds: config.ttlSeconds }
|
|
606
|
+
};
|
|
607
|
+
const makeProviderThread = (threadId, threadKey) => createAnthropicThreadManager({
|
|
608
|
+
redis,
|
|
609
|
+
threadId,
|
|
610
|
+
key: threadKey,
|
|
611
|
+
...baseExtras
|
|
612
|
+
});
|
|
613
|
+
const makeTieredBase = (threadId, threadKey) => createTieredThreadManager({
|
|
614
|
+
redis,
|
|
615
|
+
threadId,
|
|
616
|
+
key: threadKey,
|
|
617
|
+
idOf: storedMessageId,
|
|
618
|
+
...baseExtras,
|
|
619
|
+
...config.coldStore && { coldStore: config.coldStore }
|
|
620
|
+
});
|
|
400
621
|
const threadOps = {
|
|
401
622
|
async initializeThread(threadId, threadKey) {
|
|
402
|
-
const thread =
|
|
403
|
-
redis,
|
|
404
|
-
threadId,
|
|
405
|
-
key: threadKey
|
|
406
|
-
});
|
|
623
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
407
624
|
await thread.initialize();
|
|
408
625
|
},
|
|
409
626
|
async appendHumanMessage(threadId, id, content, threadKey) {
|
|
410
|
-
const thread =
|
|
411
|
-
redis,
|
|
412
|
-
threadId,
|
|
413
|
-
key: threadKey
|
|
414
|
-
});
|
|
627
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
415
628
|
await thread.appendUserMessage(id, content);
|
|
416
629
|
},
|
|
417
630
|
async appendSystemMessage(threadId, id, content, threadKey) {
|
|
418
|
-
const thread =
|
|
419
|
-
redis,
|
|
420
|
-
threadId,
|
|
421
|
-
key: threadKey
|
|
422
|
-
});
|
|
631
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
423
632
|
await thread.appendSystemMessage(id, content);
|
|
424
633
|
},
|
|
425
634
|
async appendToolResult(id, cfg) {
|
|
426
635
|
const { threadId, threadKey, toolCallId, toolName, content } = cfg;
|
|
427
|
-
const thread =
|
|
428
|
-
redis,
|
|
429
|
-
threadId,
|
|
430
|
-
key: threadKey
|
|
431
|
-
});
|
|
636
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
432
637
|
await thread.appendToolResult(id, toolCallId, toolName, content);
|
|
433
638
|
},
|
|
434
639
|
async appendAgentMessage(threadId, id, message, threadKey) {
|
|
435
|
-
const thread =
|
|
436
|
-
redis,
|
|
437
|
-
threadId,
|
|
438
|
-
key: threadKey
|
|
439
|
-
});
|
|
640
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
440
641
|
await thread.appendAssistantMessage(id, message.content);
|
|
441
642
|
},
|
|
442
643
|
async forkThread(sourceThreadId, targetThreadId, threadKey) {
|
|
@@ -444,29 +645,30 @@ function createAnthropicAdapter(config) {
|
|
|
444
645
|
redis,
|
|
445
646
|
threadId: sourceThreadId,
|
|
446
647
|
key: threadKey,
|
|
447
|
-
hooks: config.hooks
|
|
648
|
+
hooks: config.hooks,
|
|
649
|
+
...baseExtras
|
|
448
650
|
});
|
|
449
651
|
await thread.fork(targetThreadId);
|
|
450
652
|
},
|
|
451
653
|
async truncateThread(threadId, messageId, threadKey) {
|
|
452
|
-
const thread =
|
|
654
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
453
655
|
await thread.truncateFromId(messageId);
|
|
454
656
|
},
|
|
455
657
|
async loadThreadState(threadId, threadKey) {
|
|
456
|
-
const thread =
|
|
457
|
-
redis,
|
|
458
|
-
threadId,
|
|
459
|
-
key: threadKey
|
|
460
|
-
});
|
|
658
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
461
659
|
return thread.loadState();
|
|
462
660
|
},
|
|
463
661
|
async saveThreadState(threadId, state, threadKey) {
|
|
464
|
-
const thread =
|
|
465
|
-
redis,
|
|
466
|
-
threadId,
|
|
467
|
-
key: threadKey
|
|
468
|
-
});
|
|
662
|
+
const thread = makeProviderThread(threadId, threadKey);
|
|
469
663
|
await thread.saveState(state);
|
|
664
|
+
},
|
|
665
|
+
async hydrateThread(threadId, threadKey) {
|
|
666
|
+
if (!config.coldStore) return;
|
|
667
|
+
await makeTieredBase(threadId, threadKey).hydrate();
|
|
668
|
+
},
|
|
669
|
+
async flushThread(threadId, threadKey) {
|
|
670
|
+
if (!config.coldStore) return;
|
|
671
|
+
await makeTieredBase(threadId, threadKey).flush();
|
|
470
672
|
}
|
|
471
673
|
};
|
|
472
674
|
function createActivities(scope) {
|
|
@@ -476,13 +678,14 @@ function createAnthropicAdapter(config) {
|
|
|
476
678
|
Object.entries(threadOps).map(([k, v]) => [`${prefix}${cap(k)}`, v])
|
|
477
679
|
);
|
|
478
680
|
}
|
|
479
|
-
const makeInvoker = (model, maxTokens) => {
|
|
681
|
+
const makeInvoker = (model, maxTokens, promptCache) => {
|
|
480
682
|
const invokerConfig = {
|
|
481
683
|
redis,
|
|
482
684
|
client,
|
|
483
685
|
model,
|
|
484
686
|
...maxTokens !== void 0 ? { maxTokens } : {},
|
|
485
687
|
...config.maxTokens !== void 0 && maxTokens === void 0 ? { maxTokens: config.maxTokens } : {},
|
|
688
|
+
...promptCache !== void 0 ? { promptCache } : config.promptCache !== void 0 ? { promptCache: config.promptCache } : {},
|
|
486
689
|
hooks: config.hooks
|
|
487
690
|
};
|
|
488
691
|
return createAnthropicModelInvoker(invokerConfig);
|
|
@@ -500,6 +703,6 @@ function createAnthropicAdapter(config) {
|
|
|
500
703
|
};
|
|
501
704
|
}
|
|
502
705
|
|
|
503
|
-
export { ADAPTER_ID, createAnthropicAdapter, createAnthropicModelInvoker, createAnthropicThreadManager, invokeAnthropicModel };
|
|
706
|
+
export { ADAPTER_ID, addPromptCacheControl, createAnthropicAdapter, createAnthropicModelInvoker, createAnthropicThreadManager, invokeAnthropicModel, resolvePromptCacheOptions };
|
|
504
707
|
//# sourceMappingURL=index.js.map
|
|
505
708
|
//# sourceMappingURL=index.js.map
|