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