@tanstack/ai-persistence 0.6.7 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/middleware.js +39 -2
- package/dist/esm/middleware.js.map +1 -1
- package/dist/esm/reconstruct.d.ts +19 -1
- package/dist/esm/reconstruct.js +39 -3
- package/dist/esm/reconstruct.js.map +1 -1
- package/dist/esm/testkit/conformance.d.ts +17 -0
- package/dist/esm/testkit/conformance.js +41 -0
- package/dist/esm/testkit/conformance.js.map +1 -1
- package/dist/esm/types.js +2 -2
- package/package.json +4 -3
- package/src/middleware.ts +58 -5
- package/src/reconstruct.ts +74 -2
- package/src/testkit/conformance.ts +76 -0
package/dist/esm/middleware.js
CHANGED
|
@@ -24,6 +24,39 @@ function generationScope(ctx, opts) {
|
|
|
24
24
|
var DEFAULT_ARTIFACT_FETCH_TIMEOUT_MS = 3e4;
|
|
25
25
|
var DEFAULT_MAX_ARTIFACT_BYTES = 1073741824;
|
|
26
26
|
var runState = /* @__PURE__ */ new WeakMap();
|
|
27
|
+
/** `metadata.tanstack.run.id` of a stored message, when set. */
|
|
28
|
+
function runTagOf(message) {
|
|
29
|
+
const tanstack = message.metadata?.tanstack;
|
|
30
|
+
if (typeof tanstack !== "object" || tanstack === null) return;
|
|
31
|
+
const run = tanstack.run;
|
|
32
|
+
if (typeof run !== "object" || run === null) return;
|
|
33
|
+
const id = run.id;
|
|
34
|
+
return typeof id === "string" && id !== "" ? id : void 0;
|
|
35
|
+
}
|
|
36
|
+
function withRunTag(message, runId) {
|
|
37
|
+
const metadata = message.metadata ?? {};
|
|
38
|
+
const tanstack = metadata.tanstack;
|
|
39
|
+
return {
|
|
40
|
+
...message,
|
|
41
|
+
metadata: {
|
|
42
|
+
...metadata,
|
|
43
|
+
tanstack: {
|
|
44
|
+
...typeof tanstack === "object" && tanstack !== null ? tanstack : {},
|
|
45
|
+
run: { id: runId }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The thread to save, with this run's id on the assistant messages it added
|
|
52
|
+
* (`metadata.tanstack.run.id`). `reconstructChat` uses it to match each
|
|
53
|
+
* message to its run. Messages from earlier runs are left as they are.
|
|
54
|
+
*/
|
|
55
|
+
function runMessages(ctx, state) {
|
|
56
|
+
const from = state?.firstRunMessage;
|
|
57
|
+
if (from === void 0) return [...ctx.messages];
|
|
58
|
+
return ctx.messages.map((message, index) => index >= from && message.role === "assistant" && runTagOf(message) === void 0 ? withRunTag(message, ctx.runId) : message);
|
|
59
|
+
}
|
|
27
60
|
var validResumeStatuses = /* @__PURE__ */ new Set(["resolved", "cancelled"]);
|
|
28
61
|
function mergeMaps(left, right) {
|
|
29
62
|
if (!left && !right) return void 0;
|
|
@@ -39,6 +72,7 @@ function mergeResumeToolState(left, right) {
|
|
|
39
72
|
return {
|
|
40
73
|
approvals: mergeMaps(left.approvals, right.approvals),
|
|
41
74
|
clientToolResults: mergeMaps(left.clientToolResults, right.clientToolResults),
|
|
75
|
+
clientToolErrors: mergeMaps(left.clientToolErrors, right.clientToolErrors),
|
|
42
76
|
genericInterrupts: mergeMaps(left.genericInterrupts, right.genericInterrupts),
|
|
43
77
|
genericInterruptRequests: mergeMaps(left.genericInterruptRequests, right.genericInterruptRequests),
|
|
44
78
|
deniedToolResults: mergeMaps(left.deniedToolResults, right.deniedToolResults),
|
|
@@ -321,6 +355,7 @@ function resumeToolStateFromPending(pending, resumeByInterruptId) {
|
|
|
321
355
|
for (const interrupt of pending) {
|
|
322
356
|
const entry = resumeByInterruptId.get(interrupt.interruptId);
|
|
323
357
|
if (!entry) continue;
|
|
358
|
+
if (hasReservedInterruptBinding(interrupt.payload)) continue;
|
|
324
359
|
const kind = interruptKind(interrupt);
|
|
325
360
|
const reason = stringField(interrupt.payload, "reason");
|
|
326
361
|
const toolCallId = stringField(interrupt.payload, "toolCallId");
|
|
@@ -1075,6 +1110,8 @@ function withPersistence(persistence, options = {}) {
|
|
|
1075
1110
|
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
1076
1111
|
},
|
|
1077
1112
|
async onStart(ctx) {
|
|
1113
|
+
const state = runState.get(ctx);
|
|
1114
|
+
if (state) state.firstRunMessage = ctx.messages.length;
|
|
1078
1115
|
try {
|
|
1079
1116
|
await messageStore.saveThread(ctx.threadId, [...ctx.messages]);
|
|
1080
1117
|
} catch {}
|
|
@@ -1131,7 +1168,7 @@ function withPersistence(persistence, options = {}) {
|
|
|
1131
1168
|
const usage = ctx.phase === "modelStream" && chunkUsage ? accumulateTokenUsage(state.usage, chunkUsage) : state.usage ?? chunkUsage;
|
|
1132
1169
|
state.usage = usage;
|
|
1133
1170
|
await interruptRun(runs, ctx.runId, usage);
|
|
1134
|
-
await messageStore.saveThread(ctx.threadId,
|
|
1171
|
+
await messageStore.saveThread(ctx.threadId, runMessages(ctx, state));
|
|
1135
1172
|
state.interrupted = true;
|
|
1136
1173
|
},
|
|
1137
1174
|
onUsage(ctx, usage) {
|
|
@@ -1143,7 +1180,7 @@ function withPersistence(persistence, options = {}) {
|
|
|
1143
1180
|
const state = runState.get(ctx);
|
|
1144
1181
|
if (state?.interrupted) return;
|
|
1145
1182
|
try {
|
|
1146
|
-
await messageStore.saveThread(ctx.threadId,
|
|
1183
|
+
await messageStore.saveThread(ctx.threadId, runMessages(ctx, state));
|
|
1147
1184
|
await commitPendingResumes(state, persistence.stores.interrupts);
|
|
1148
1185
|
await completeRun(runs, ctx.runId, state?.usage ?? info.usage);
|
|
1149
1186
|
state?.completion?.resolve();
|