@deepagents/context 7.1.0 → 7.1.2
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/browser.js +7 -4
- package/dist/browser.js.map +2 -2
- package/dist/index.js +341 -449
- package/dist/index.js.map +4 -4
- package/dist/lib/chain-summary.d.ts +2 -6
- package/dist/lib/chain-summary.d.ts.map +1 -1
- package/dist/lib/engine.d.ts +1 -1
- package/dist/lib/engine.d.ts.map +1 -1
- package/dist/lib/estimate.d.ts.map +1 -1
- package/dist/lib/fragments.d.ts +8 -6
- package/dist/lib/fragments.d.ts.map +1 -1
- package/dist/lib/resolvers/index.d.ts +0 -1
- package/dist/lib/resolvers/index.d.ts.map +1 -1
- package/dist/lib/save/save-pipeline.d.ts +2 -2
- package/dist/lib/save/save-pipeline.d.ts.map +1 -1
- package/dist/lib/store/ddl.sqlserver.d.ts.map +1 -1
- package/dist/lib/store/postgres.store.d.ts +3 -2
- package/dist/lib/store/postgres.store.d.ts.map +1 -1
- package/dist/lib/store/sqlserver.store.d.ts +3 -2
- package/dist/lib/store/sqlserver.store.d.ts.map +1 -1
- package/dist/lib/stream/postgres-notify-change-source.d.ts +3 -2
- package/dist/lib/stream/postgres-notify-change-source.d.ts.map +1 -1
- package/dist/lib/stream/postgres.stream-store.d.ts +3 -2
- package/dist/lib/stream/postgres.stream-store.d.ts.map +1 -1
- package/dist/lib/stream/sqlite.stream-store.d.ts.map +1 -1
- package/dist/lib/tracing/batch-processor.d.ts.map +1 -1
- package/dist/lib/tracing/index.js +49 -29
- package/dist/lib/tracing/index.js.map +2 -2
- package/package.json +12 -5
- package/dist/lib/resolvers/promise-resolver.d.ts +0 -7
- package/dist/lib/resolvers/promise-resolver.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -175,7 +175,7 @@ function fitsFragmentData(value, visited) {
|
|
|
175
175
|
if (Array.isArray(value)) {
|
|
176
176
|
return value.every((item) => fitsFragmentData(item, visited));
|
|
177
177
|
}
|
|
178
|
-
if (value instanceof Promise) return
|
|
178
|
+
if (value instanceof Promise) return false;
|
|
179
179
|
if (Symbol.asyncIterator in value || Symbol.iterator in value) return true;
|
|
180
180
|
if (isFragment(value)) return fitsFragmentData(value.data, visited);
|
|
181
181
|
return Object.values(value).every((item) => fitsFragmentData(item, visited));
|
|
@@ -2647,6 +2647,7 @@ import {
|
|
|
2647
2647
|
isStaticToolUIPart as isStaticToolUIPart2,
|
|
2648
2648
|
validateUIMessages
|
|
2649
2649
|
} from "ai";
|
|
2650
|
+
import pMemoize2 from "p-memoize";
|
|
2650
2651
|
|
|
2651
2652
|
// packages/context/src/lib/ui-message-guards.ts
|
|
2652
2653
|
function isRecord2(value) {
|
|
@@ -2679,75 +2680,63 @@ function mergeReply(segments) {
|
|
|
2679
2680
|
parts: segments.flatMap((segment) => segment.parts)
|
|
2680
2681
|
};
|
|
2681
2682
|
}
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
#firedOnceIds = /* @__PURE__ */ new Set();
|
|
2692
|
-
ingestStored(msg) {
|
|
2693
|
-
this.#messageCount++;
|
|
2683
|
+
function summarizeChain(stored, pending) {
|
|
2684
|
+
let turn = 0;
|
|
2685
|
+
let lastMessageAt;
|
|
2686
|
+
let lastMessage;
|
|
2687
|
+
const assistantMessages = [];
|
|
2688
|
+
let reply = [];
|
|
2689
|
+
const replies = [reply];
|
|
2690
|
+
const firedOnceIds = /* @__PURE__ */ new Set();
|
|
2691
|
+
for (const msg of stored) {
|
|
2694
2692
|
if (msg.name === "assistant") {
|
|
2695
2693
|
const message3 = requireUIMessage(
|
|
2696
2694
|
msg.data,
|
|
2697
2695
|
`Stored assistant message "${msg.id}"`
|
|
2698
2696
|
);
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
if (open && !this.#replyClosed) open.push(message3);
|
|
2703
|
-
else {
|
|
2704
|
-
this.#replies.push([message3]);
|
|
2705
|
-
this.#replyClosed = false;
|
|
2706
|
-
}
|
|
2707
|
-
return;
|
|
2708
|
-
}
|
|
2709
|
-
if (msg.name !== "user") {
|
|
2710
|
-
return;
|
|
2697
|
+
assistantMessages.push(message3);
|
|
2698
|
+
reply.push(message3);
|
|
2699
|
+
continue;
|
|
2711
2700
|
}
|
|
2701
|
+
if (msg.name !== "user") continue;
|
|
2712
2702
|
const message2 = requireUIMessage(
|
|
2713
2703
|
msg.data,
|
|
2714
2704
|
`Stored user message "${msg.id}"`
|
|
2715
2705
|
);
|
|
2716
2706
|
if (isSyntheticReminderMessage(message2)) {
|
|
2717
2707
|
for (const id of message2.metadata.synthetic.onceIds ?? []) {
|
|
2718
|
-
|
|
2708
|
+
firedOnceIds.add(id);
|
|
2719
2709
|
}
|
|
2720
|
-
|
|
2710
|
+
continue;
|
|
2721
2711
|
}
|
|
2722
|
-
for (const id of getReminderOnceIds(message2))
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2712
|
+
for (const id of getReminderOnceIds(message2)) firedOnceIds.add(id);
|
|
2713
|
+
turn++;
|
|
2714
|
+
lastMessageAt = msg.createdAt;
|
|
2715
|
+
lastMessage = message2;
|
|
2716
|
+
reply = [];
|
|
2717
|
+
replies.push(reply);
|
|
2727
2718
|
}
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
if (fragment2.name !== "user") return;
|
|
2719
|
+
for (const fragment2 of pending) {
|
|
2720
|
+
if (fragment2.name !== "user") continue;
|
|
2731
2721
|
const encoded = fragment2.codec?.encode();
|
|
2732
|
-
if (isUIMessage(encoded) && isSyntheticReminderMessage(encoded))
|
|
2733
|
-
|
|
2734
|
-
}
|
|
2735
|
-
build() {
|
|
2736
|
-
return {
|
|
2737
|
-
turn: this.#turn,
|
|
2738
|
-
messageCount: this.#messageCount,
|
|
2739
|
-
lastMessageAt: this.#lastMessageAt,
|
|
2740
|
-
lastMessage: this.#lastMessage,
|
|
2741
|
-
lastAssistantMessage: this.#lastAssistantMessage,
|
|
2742
|
-
lastAssistantMessages: this.#lastAssistantMessages,
|
|
2743
|
-
lastAssistantReplies: this.#replies.map(mergeReply),
|
|
2744
|
-
firedOnceIds: this.#firedOnceIds
|
|
2745
|
-
};
|
|
2722
|
+
if (isUIMessage(encoded) && isSyntheticReminderMessage(encoded)) continue;
|
|
2723
|
+
turn++;
|
|
2746
2724
|
}
|
|
2747
|
-
|
|
2725
|
+
return {
|
|
2726
|
+
turn,
|
|
2727
|
+
messageCount: stored.length + pending.length,
|
|
2728
|
+
lastMessageAt,
|
|
2729
|
+
lastMessage,
|
|
2730
|
+
lastAssistantMessage: assistantMessages.at(-1),
|
|
2731
|
+
lastAssistantMessages: assistantMessages,
|
|
2732
|
+
lastAssistantReplies: replies.filter((segments) => segments.length > 0).map(mergeReply),
|
|
2733
|
+
firedOnceIds
|
|
2734
|
+
};
|
|
2735
|
+
}
|
|
2748
2736
|
|
|
2749
2737
|
// packages/context/src/lib/estimate.ts
|
|
2750
2738
|
import { encode } from "gpt-tokenizer";
|
|
2739
|
+
import pMemoize from "p-memoize";
|
|
2751
2740
|
import { z as z2 } from "zod";
|
|
2752
2741
|
var defaultTokenizer = {
|
|
2753
2742
|
encode(text) {
|
|
@@ -2789,14 +2778,17 @@ function inputPricePerMillion(model) {
|
|
|
2789
2778
|
}
|
|
2790
2779
|
var ModelsRegistry = class {
|
|
2791
2780
|
#cache = /* @__PURE__ */ new Map();
|
|
2792
|
-
#loaded = false;
|
|
2793
2781
|
#tokenizers = /* @__PURE__ */ new Map();
|
|
2794
2782
|
#defaultTokenizer = defaultTokenizer;
|
|
2783
|
+
/** Fetches once; concurrent calls share the fetch, and a failed one runs again. */
|
|
2784
|
+
#load = pMemoize(() => this.#fetchModels());
|
|
2795
2785
|
/**
|
|
2796
2786
|
* Load models data from models.dev API
|
|
2797
2787
|
*/
|
|
2798
2788
|
async load() {
|
|
2799
|
-
|
|
2789
|
+
await this.#load();
|
|
2790
|
+
}
|
|
2791
|
+
async #fetchModels() {
|
|
2800
2792
|
const response = await fetch("https://models.dev/api.json");
|
|
2801
2793
|
if (!response.ok) {
|
|
2802
2794
|
throw new Error(`Failed to fetch models: ${response.statusText}`);
|
|
@@ -2815,7 +2807,6 @@ var ModelsRegistry = class {
|
|
|
2815
2807
|
this.#cache.set(`${providerId}:${modelId}`, info);
|
|
2816
2808
|
}
|
|
2817
2809
|
}
|
|
2818
|
-
this.#loaded = true;
|
|
2819
2810
|
}
|
|
2820
2811
|
/**
|
|
2821
2812
|
* Get model info by ID
|
|
@@ -3059,20 +3050,6 @@ function pushLimited2(collected, chunk, maxItems, resolverName) {
|
|
|
3059
3050
|
collected.push(chunk);
|
|
3060
3051
|
}
|
|
3061
3052
|
|
|
3062
|
-
// packages/context/src/lib/resolvers/promise-resolver.ts
|
|
3063
|
-
var PromiseResolver = class {
|
|
3064
|
-
name = "PromiseResolver";
|
|
3065
|
-
canResolve(value) {
|
|
3066
|
-
return value instanceof Promise;
|
|
3067
|
-
}
|
|
3068
|
-
async resolve(value, _ctx) {
|
|
3069
|
-
if (!this.canResolve(value)) {
|
|
3070
|
-
throw new TypeError(`${this.name} cannot resolve a ${typeof value}`);
|
|
3071
|
-
}
|
|
3072
|
-
return value;
|
|
3073
|
-
}
|
|
3074
|
-
};
|
|
3075
|
-
|
|
3076
3053
|
// packages/context/src/lib/resolvers/loader-resolver.ts
|
|
3077
3054
|
var FragmentLoaderResolver = class {
|
|
3078
3055
|
#resolvers;
|
|
@@ -3207,7 +3184,6 @@ function defaultResolvers() {
|
|
|
3207
3184
|
new AsyncResolver(),
|
|
3208
3185
|
new GeneratorResolver(),
|
|
3209
3186
|
new FunctionResolver(),
|
|
3210
|
-
new PromiseResolver(),
|
|
3211
3187
|
new IterableResolver()
|
|
3212
3188
|
];
|
|
3213
3189
|
}
|
|
@@ -3224,14 +3200,14 @@ var HeadConflictError = class extends Error {
|
|
|
3224
3200
|
var SavePipeline = class _SavePipeline {
|
|
3225
3201
|
#engine;
|
|
3226
3202
|
#pending;
|
|
3227
|
-
#shouldBranch
|
|
3228
|
-
constructor(engine, pending) {
|
|
3203
|
+
#shouldBranch;
|
|
3204
|
+
constructor(engine, pending, shouldBranch) {
|
|
3229
3205
|
this.#engine = engine;
|
|
3230
3206
|
this.#pending = pending;
|
|
3231
|
-
}
|
|
3232
|
-
async applyUpdateBranching(shouldBranch) {
|
|
3233
3207
|
this.#shouldBranch = shouldBranch;
|
|
3234
|
-
|
|
3208
|
+
}
|
|
3209
|
+
async applyUpdateBranching() {
|
|
3210
|
+
if (!this.#shouldBranch) return this;
|
|
3235
3211
|
for (const fragment2 of this.#pending) {
|
|
3236
3212
|
if (!fragment2.id) continue;
|
|
3237
3213
|
const existing = await this.#engine.store.getMessage(fragment2.id);
|
|
@@ -4101,6 +4077,25 @@ function mergeTerminalToolParts(message2, liveParts) {
|
|
|
4101
4077
|
parts.push(...remaining.values());
|
|
4102
4078
|
return { ...message2, parts };
|
|
4103
4079
|
}
|
|
4080
|
+
var UNOPENED = {
|
|
4081
|
+
chat: null,
|
|
4082
|
+
branchName: "main",
|
|
4083
|
+
headMessageId: void 0
|
|
4084
|
+
};
|
|
4085
|
+
var OpenChat = class {
|
|
4086
|
+
chat;
|
|
4087
|
+
branch;
|
|
4088
|
+
constructor(chat2, branch) {
|
|
4089
|
+
this.chat = chat2;
|
|
4090
|
+
this.branch = branch;
|
|
4091
|
+
}
|
|
4092
|
+
get branchName() {
|
|
4093
|
+
return this.branch.name;
|
|
4094
|
+
}
|
|
4095
|
+
get headMessageId() {
|
|
4096
|
+
return this.branch.headMessageId ?? void 0;
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
4104
4099
|
var ContextEngine = class _ContextEngine {
|
|
4105
4100
|
/** Non-message fragments (role, hints, etc.) - not persisted in graph */
|
|
4106
4101
|
#fragments = [];
|
|
@@ -4109,23 +4104,13 @@ var ContextEngine = class _ContextEngine {
|
|
|
4109
4104
|
#store;
|
|
4110
4105
|
#chatId;
|
|
4111
4106
|
#userId;
|
|
4112
|
-
|
|
4113
|
-
#
|
|
4114
|
-
|
|
4115
|
-
#
|
|
4116
|
-
/** Initial metadata to merge on first initialization */
|
|
4117
|
-
#initialMetadata;
|
|
4107
|
+
/** What this engine knows of its chat: nothing until the first store call opens it. */
|
|
4108
|
+
#session = UNOPENED;
|
|
4109
|
+
/** Opens the chat once; concurrent first calls share it, and a failed open runs again. */
|
|
4110
|
+
#open;
|
|
4118
4111
|
#loaderResolver;
|
|
4119
4112
|
/** Retained so forked children inherit the parent's resolver chain */
|
|
4120
4113
|
#resolvers;
|
|
4121
|
-
get #activeBranch() {
|
|
4122
|
-
if (!this.#branch) {
|
|
4123
|
-
throw new Error(
|
|
4124
|
-
"Branch not initialized. Call #ensureInitialized() first."
|
|
4125
|
-
);
|
|
4126
|
-
}
|
|
4127
|
-
return this.#branch;
|
|
4128
|
-
}
|
|
4129
4114
|
get #renderableFragments() {
|
|
4130
4115
|
return this.#fragments.filter((f) => !isConditionalReminder(f));
|
|
4131
4116
|
}
|
|
@@ -4139,38 +4124,30 @@ var ContextEngine = class _ContextEngine {
|
|
|
4139
4124
|
this.#store = options.store;
|
|
4140
4125
|
this.#chatId = options.chatId;
|
|
4141
4126
|
this.#userId = options.userId;
|
|
4142
|
-
this.#
|
|
4143
|
-
this.#initialMetadata = options.metadata;
|
|
4127
|
+
this.#open = pMemoize2(() => this.#openChat(options.metadata));
|
|
4144
4128
|
this.#resolvers = options.resolvers;
|
|
4145
4129
|
this.#loaderResolver = new FragmentLoaderResolver(
|
|
4146
4130
|
options.resolvers ?? defaultResolvers()
|
|
4147
4131
|
);
|
|
4148
4132
|
}
|
|
4149
4133
|
/**
|
|
4150
|
-
*
|
|
4134
|
+
* Creates the chat if it is new, checks its owner, merges the initial
|
|
4135
|
+
* metadata, and reads the active branch.
|
|
4151
4136
|
*/
|
|
4152
|
-
async #
|
|
4153
|
-
|
|
4154
|
-
return;
|
|
4155
|
-
}
|
|
4156
|
-
this.#chatData = await this.#store.upsertChat({
|
|
4137
|
+
async #openChat(metadata) {
|
|
4138
|
+
let chat2 = await this.#store.upsertChat({
|
|
4157
4139
|
id: this.#chatId,
|
|
4158
4140
|
userId: this.#userId
|
|
4159
4141
|
});
|
|
4160
|
-
if (
|
|
4142
|
+
if (chat2.userId !== this.#userId) {
|
|
4161
4143
|
throw new Error(
|
|
4162
|
-
`chat "${this.#chatId}" belongs to user "${
|
|
4144
|
+
`chat "${this.#chatId}" belongs to user "${chat2.userId}", not "${this.#userId}"`
|
|
4163
4145
|
);
|
|
4164
4146
|
}
|
|
4165
|
-
if (
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
({ metadata }) => ({
|
|
4170
|
-
metadata: { ...metadata, ...initialMetadata }
|
|
4171
|
-
})
|
|
4172
|
-
);
|
|
4173
|
-
this.#initialMetadata = void 0;
|
|
4147
|
+
if (metadata) {
|
|
4148
|
+
chat2 = await this.#store.updateChat(this.#chatId, (stored) => ({
|
|
4149
|
+
metadata: { ...stored.metadata, ...metadata }
|
|
4150
|
+
}));
|
|
4174
4151
|
}
|
|
4175
4152
|
const branch = await this.#store.getActiveBranch(this.#chatId);
|
|
4176
4153
|
if (!branch) {
|
|
@@ -4178,20 +4155,21 @@ var ContextEngine = class _ContextEngine {
|
|
|
4178
4155
|
`Active branch not found for chat "${this.#chatId}" after upsertChat`
|
|
4179
4156
|
);
|
|
4180
4157
|
}
|
|
4181
|
-
|
|
4182
|
-
this.#
|
|
4183
|
-
|
|
4158
|
+
const open = new OpenChat(chat2, branch);
|
|
4159
|
+
this.#session = open;
|
|
4160
|
+
return open;
|
|
4184
4161
|
}
|
|
4185
4162
|
/**
|
|
4186
4163
|
* Create a new branch from a specific message.
|
|
4187
4164
|
* Shared logic between rewind() and btw().
|
|
4188
4165
|
*/
|
|
4189
|
-
async #createBranchFrom(messageId, switchTo) {
|
|
4166
|
+
async #createBranchFrom(open, messageId, switchTo) {
|
|
4190
4167
|
const branches = await this.#store.listBranches(this.#chatId);
|
|
4168
|
+
const baseName = open.branch.name;
|
|
4191
4169
|
const samePrefix = branches.filter(
|
|
4192
|
-
(it) => it.name ===
|
|
4170
|
+
(it) => it.name === baseName || it.name.startsWith(`${baseName}-v`)
|
|
4193
4171
|
);
|
|
4194
|
-
const newBranchName = `${
|
|
4172
|
+
const newBranchName = `${baseName}-v${samePrefix.length + 1}`;
|
|
4195
4173
|
const newBranch = {
|
|
4196
4174
|
id: crypto.randomUUID(),
|
|
4197
4175
|
chatId: this.#chatId,
|
|
@@ -4203,8 +4181,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
4203
4181
|
await this.#store.createBranch(newBranch);
|
|
4204
4182
|
if (switchTo) {
|
|
4205
4183
|
await this.#store.setActiveBranch(this.#chatId, newBranch.id);
|
|
4206
|
-
|
|
4207
|
-
this.#branchName = newBranchName;
|
|
4184
|
+
open.branch = { ...newBranch, isActive: true };
|
|
4208
4185
|
this.#pendingMessages = [];
|
|
4209
4186
|
}
|
|
4210
4187
|
const chain = await this.#store.getMessageChain(messageId);
|
|
@@ -4236,47 +4213,40 @@ var ContextEngine = class _ContextEngine {
|
|
|
4236
4213
|
* Get the current branch name.
|
|
4237
4214
|
*/
|
|
4238
4215
|
get branch() {
|
|
4239
|
-
return this.#branchName;
|
|
4216
|
+
return this.#session.branchName;
|
|
4240
4217
|
}
|
|
4241
4218
|
/**
|
|
4242
4219
|
* Get the current branch head message ID.
|
|
4243
4220
|
* Returns undefined if no messages have been saved yet.
|
|
4244
4221
|
*/
|
|
4245
4222
|
get headMessageId() {
|
|
4246
|
-
return this.#
|
|
4223
|
+
return this.#session.headMessageId;
|
|
4247
4224
|
}
|
|
4248
4225
|
/**
|
|
4249
4226
|
* Get metadata for the current chat.
|
|
4250
4227
|
* Returns null if the chat hasn't been initialized yet.
|
|
4251
4228
|
*/
|
|
4252
4229
|
get chat() {
|
|
4253
|
-
return this.#
|
|
4230
|
+
return this.#session.chat;
|
|
4254
4231
|
}
|
|
4255
4232
|
/**
|
|
4256
4233
|
* Count user turns in the conversation and return the previous saved user message context.
|
|
4257
4234
|
* Includes persisted messages and pending messages in the turn count.
|
|
4258
4235
|
*/
|
|
4259
4236
|
async #getChainContext(pending = this.#pendingMessages) {
|
|
4260
|
-
await this.#
|
|
4261
|
-
const
|
|
4262
|
-
|
|
4263
|
-
const chain = await this.#store.getMessageChain(
|
|
4264
|
-
this.#branch.headMessageId
|
|
4265
|
-
);
|
|
4266
|
-
for (const msg of chain) builder.ingestStored(msg);
|
|
4267
|
-
}
|
|
4268
|
-
for (const fragment2 of pending) builder.ingestPending(fragment2);
|
|
4269
|
-
return builder.build();
|
|
4237
|
+
const open = await this.#open();
|
|
4238
|
+
const stored = open.branch.headMessageId ? await this.#store.getMessageChain(open.branch.headMessageId) : [];
|
|
4239
|
+
return summarizeChain(stored, pending);
|
|
4270
4240
|
}
|
|
4271
4241
|
async getTurnCount() {
|
|
4272
4242
|
const { turn } = await this.#getChainContext();
|
|
4273
4243
|
return turn;
|
|
4274
4244
|
}
|
|
4275
4245
|
async firstUserMessage() {
|
|
4276
|
-
await this.#
|
|
4277
|
-
if (
|
|
4246
|
+
const open = await this.#open();
|
|
4247
|
+
if (open.branch.headMessageId) {
|
|
4278
4248
|
const chain = await this.#store.getMessageChain(
|
|
4279
|
-
|
|
4249
|
+
open.branch.headMessageId
|
|
4280
4250
|
);
|
|
4281
4251
|
for (const msg of chain) {
|
|
4282
4252
|
if (msg.name === "user") {
|
|
@@ -4305,7 +4275,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
4305
4275
|
* @throws if the pending tail is missing an id (programming error).
|
|
4306
4276
|
*/
|
|
4307
4277
|
async headMessage() {
|
|
4308
|
-
await this.#
|
|
4278
|
+
const open = await this.#open();
|
|
4309
4279
|
if (this.#pendingMessages.length > 0) {
|
|
4310
4280
|
const tail = this.#pendingMessages[this.#pendingMessages.length - 1];
|
|
4311
4281
|
if (!tail.id) {
|
|
@@ -4315,8 +4285,8 @@ var ContextEngine = class _ContextEngine {
|
|
|
4315
4285
|
}
|
|
4316
4286
|
return { id: tail.id, name: tail.name };
|
|
4317
4287
|
}
|
|
4318
|
-
if (
|
|
4319
|
-
const msg = await this.#store.getMessage(
|
|
4288
|
+
if (open.branch.headMessageId) {
|
|
4289
|
+
const msg = await this.#store.getMessage(open.branch.headMessageId);
|
|
4320
4290
|
if (msg) return { id: msg.id, name: msg.name };
|
|
4321
4291
|
}
|
|
4322
4292
|
return void 0;
|
|
@@ -4336,12 +4306,12 @@ var ContextEngine = class _ContextEngine {
|
|
|
4336
4306
|
* For id-lookup use `headMessage()` instead — that one keeps placeholders.
|
|
4337
4307
|
*/
|
|
4338
4308
|
async getMessages() {
|
|
4339
|
-
await this.#
|
|
4309
|
+
const open = await this.#open();
|
|
4340
4310
|
const messages = [];
|
|
4341
4311
|
const indexById = /* @__PURE__ */ new Map();
|
|
4342
|
-
if (
|
|
4312
|
+
if (open.branch.headMessageId) {
|
|
4343
4313
|
const chain = await this.#store.getMessageChain(
|
|
4344
|
-
|
|
4314
|
+
open.branch.headMessageId
|
|
4345
4315
|
);
|
|
4346
4316
|
for (const msg of chain) {
|
|
4347
4317
|
const data = requireUIMessage(msg.data, `Stored message "${msg.id}"`);
|
|
@@ -4452,7 +4422,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
4452
4422
|
* ```
|
|
4453
4423
|
*/
|
|
4454
4424
|
async resolve(options) {
|
|
4455
|
-
await this.#
|
|
4425
|
+
await this.#open();
|
|
4456
4426
|
await this.#loaderResolver.resolve(this.#fragments, {
|
|
4457
4427
|
sandbox: options.sandbox,
|
|
4458
4428
|
context: this,
|
|
@@ -4477,15 +4447,19 @@ var ContextEngine = class _ContextEngine {
|
|
|
4477
4447
|
* ```
|
|
4478
4448
|
*/
|
|
4479
4449
|
async save(options) {
|
|
4480
|
-
await this.#
|
|
4450
|
+
const open = await this.#open();
|
|
4481
4451
|
if (this.#pendingMessages.length === 0) {
|
|
4482
|
-
return { headMessageId:
|
|
4452
|
+
return { headMessageId: open.branch.headMessageId ?? void 0 };
|
|
4483
4453
|
}
|
|
4484
4454
|
const pending = this.#pendingMessages;
|
|
4485
4455
|
this.#pendingMessages = [];
|
|
4486
|
-
const pipeline = new SavePipeline(
|
|
4456
|
+
const pipeline = new SavePipeline(
|
|
4457
|
+
this.#asSavePipelineEngine(open),
|
|
4458
|
+
pending,
|
|
4459
|
+
options?.branch ?? true
|
|
4460
|
+
);
|
|
4487
4461
|
try {
|
|
4488
|
-
await pipeline.applyUpdateBranching(
|
|
4462
|
+
await pipeline.applyUpdateBranching();
|
|
4489
4463
|
await this.#foldUserReminders(pending);
|
|
4490
4464
|
return await pipeline.persist();
|
|
4491
4465
|
} catch (error) {
|
|
@@ -4726,13 +4700,14 @@ var ContextEngine = class _ContextEngine {
|
|
|
4726
4700
|
return this.#fragments.filter(isConditionalReminder).map((fragment2) => fragment2.metadata.reminder).filter((config) => config.target === target);
|
|
4727
4701
|
}
|
|
4728
4702
|
#buildBaseWhenCtx(chain) {
|
|
4729
|
-
const
|
|
4730
|
-
|
|
4731
|
-
const elapsed = chain.lastMessageAt !== void 0 ? Date.now() - chain.lastMessageAt : void 0;
|
|
4732
|
-
const chatData = this.#chatData;
|
|
4733
|
-
if (!chatData) {
|
|
4703
|
+
const session = this.#session;
|
|
4704
|
+
if (!(session instanceof OpenChat)) {
|
|
4734
4705
|
throw new Error("ContextEngine must be initialized before reminders run");
|
|
4735
4706
|
}
|
|
4707
|
+
const chatData = session.chat;
|
|
4708
|
+
const rawUsage = chatData.metadata?.usage;
|
|
4709
|
+
const usage = isLanguageModelUsage(rawUsage) ? rawUsage : void 0;
|
|
4710
|
+
const elapsed = chain.lastMessageAt !== void 0 ? Date.now() - chain.lastMessageAt : void 0;
|
|
4736
4711
|
return {
|
|
4737
4712
|
turn: chain.turn,
|
|
4738
4713
|
messageCount: chain.messageCount,
|
|
@@ -4740,7 +4715,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
4740
4715
|
lastMessage: chain.lastMessage,
|
|
4741
4716
|
chat: chatData,
|
|
4742
4717
|
usage,
|
|
4743
|
-
branch:
|
|
4718
|
+
branch: session.branchName,
|
|
4744
4719
|
elapsed
|
|
4745
4720
|
};
|
|
4746
4721
|
}
|
|
@@ -4861,36 +4836,36 @@ var ContextEngine = class _ContextEngine {
|
|
|
4861
4836
|
}
|
|
4862
4837
|
return { texts, onceIds: [...onceIds] };
|
|
4863
4838
|
}
|
|
4864
|
-
#asSavePipelineEngine() {
|
|
4839
|
+
#asSavePipelineEngine(open) {
|
|
4865
4840
|
return {
|
|
4866
4841
|
store: this.#store,
|
|
4867
4842
|
chatId: this.#chatId,
|
|
4868
4843
|
getActiveBranch: () => ({
|
|
4869
|
-
id:
|
|
4870
|
-
headMessageId:
|
|
4844
|
+
id: open.branch.id,
|
|
4845
|
+
headMessageId: open.branch.headMessageId
|
|
4871
4846
|
}),
|
|
4872
4847
|
commitHead: async (headMessageId, expectedHeadMessageId) => {
|
|
4873
4848
|
const committed = await this.#store.updateBranchHead(
|
|
4874
|
-
|
|
4849
|
+
open.branch.id,
|
|
4875
4850
|
headMessageId,
|
|
4876
4851
|
expectedHeadMessageId
|
|
4877
4852
|
);
|
|
4878
4853
|
if (committed) {
|
|
4879
|
-
|
|
4854
|
+
open.branch.headMessageId = headMessageId;
|
|
4880
4855
|
}
|
|
4881
4856
|
return committed;
|
|
4882
4857
|
},
|
|
4883
4858
|
refreshBranch: async () => {
|
|
4884
4859
|
const fresh = await this.#store.getBranch(
|
|
4885
4860
|
this.#chatId,
|
|
4886
|
-
|
|
4861
|
+
open.branch.name
|
|
4887
4862
|
);
|
|
4888
4863
|
if (!fresh) {
|
|
4889
4864
|
throw new Error(
|
|
4890
|
-
`Branch "${
|
|
4865
|
+
`Branch "${open.branch.name}" not found for chat "${this.#chatId}"`
|
|
4891
4866
|
);
|
|
4892
4867
|
}
|
|
4893
|
-
|
|
4868
|
+
open.branch = fresh;
|
|
4894
4869
|
return { id: fresh.id, headMessageId: fresh.headMessageId };
|
|
4895
4870
|
},
|
|
4896
4871
|
rewindForUpdate: (parentId) => this.#rewindForUpdate(parentId)
|
|
@@ -4909,7 +4884,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
4909
4884
|
* @returns Estimate result with token counts, costs, and per-fragment breakdown
|
|
4910
4885
|
*/
|
|
4911
4886
|
async estimate(modelId, options = {}) {
|
|
4912
|
-
await this.#
|
|
4887
|
+
const open = await this.#open();
|
|
4913
4888
|
await this.#loaderResolver.resolve(this.#fragments, {
|
|
4914
4889
|
sandbox: options.sandbox,
|
|
4915
4890
|
context: this,
|
|
@@ -4938,9 +4913,9 @@ var ContextEngine = class _ContextEngine {
|
|
|
4938
4913
|
cost
|
|
4939
4914
|
});
|
|
4940
4915
|
}
|
|
4941
|
-
if (
|
|
4916
|
+
if (open.branch.headMessageId) {
|
|
4942
4917
|
const chain = await this.#store.getMessageChain(
|
|
4943
|
-
|
|
4918
|
+
open.branch.headMessageId
|
|
4944
4919
|
);
|
|
4945
4920
|
for (const msg of chain) {
|
|
4946
4921
|
const content = estimateMessageContent(msg.data);
|
|
@@ -5012,7 +4987,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
5012
4987
|
* ```
|
|
5013
4988
|
*/
|
|
5014
4989
|
async rewind(messageId) {
|
|
5015
|
-
await this.#
|
|
4990
|
+
const open = await this.#open();
|
|
5016
4991
|
const message2 = await this.#store.getMessage(messageId);
|
|
5017
4992
|
if (!message2) {
|
|
5018
4993
|
throw new Error(`Message "${messageId}" not found`);
|
|
@@ -5020,7 +4995,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
5020
4995
|
if (message2.chatId !== this.#chatId) {
|
|
5021
4996
|
throw new Error(`Message "${messageId}" belongs to a different chat`);
|
|
5022
4997
|
}
|
|
5023
|
-
return this.#createBranchFrom(messageId, true);
|
|
4998
|
+
return this.#createBranchFrom(open, messageId, true);
|
|
5024
4999
|
}
|
|
5025
5000
|
/**
|
|
5026
5001
|
* Create a checkpoint at the current position.
|
|
@@ -5042,15 +5017,15 @@ var ContextEngine = class _ContextEngine {
|
|
|
5042
5017
|
* ```
|
|
5043
5018
|
*/
|
|
5044
5019
|
async checkpoint(name) {
|
|
5045
|
-
await this.#
|
|
5046
|
-
if (!
|
|
5020
|
+
const open = await this.#open();
|
|
5021
|
+
if (!open.branch.headMessageId) {
|
|
5047
5022
|
throw new Error("Cannot create checkpoint: no messages in conversation");
|
|
5048
5023
|
}
|
|
5049
5024
|
const checkpoint = {
|
|
5050
5025
|
id: crypto.randomUUID(),
|
|
5051
5026
|
chatId: this.#chatId,
|
|
5052
5027
|
name,
|
|
5053
|
-
messageId:
|
|
5028
|
+
messageId: open.branch.headMessageId,
|
|
5054
5029
|
createdAt: Date.now()
|
|
5055
5030
|
};
|
|
5056
5031
|
await this.#store.createCheckpoint(checkpoint);
|
|
@@ -5078,7 +5053,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
5078
5053
|
* ```
|
|
5079
5054
|
*/
|
|
5080
5055
|
async restore(name) {
|
|
5081
|
-
await this.#
|
|
5056
|
+
await this.#open();
|
|
5082
5057
|
const checkpoint = await this.#store.getCheckpoint(this.#chatId, name);
|
|
5083
5058
|
if (!checkpoint) {
|
|
5084
5059
|
throw new Error(
|
|
@@ -5103,14 +5078,13 @@ var ContextEngine = class _ContextEngine {
|
|
|
5103
5078
|
* ```
|
|
5104
5079
|
*/
|
|
5105
5080
|
async switchBranch(name) {
|
|
5106
|
-
await this.#
|
|
5081
|
+
const open = await this.#open();
|
|
5107
5082
|
const branch = await this.#store.getBranch(this.#chatId, name);
|
|
5108
5083
|
if (!branch) {
|
|
5109
5084
|
throw new Error(`Branch "${name}" not found in chat "${this.#chatId}"`);
|
|
5110
5085
|
}
|
|
5111
5086
|
await this.#store.setActiveBranch(this.#chatId, branch.id);
|
|
5112
|
-
|
|
5113
|
-
this.#branchName = name;
|
|
5087
|
+
open.branch = { ...branch, isActive: true };
|
|
5114
5088
|
this.#pendingMessages = [];
|
|
5115
5089
|
}
|
|
5116
5090
|
/**
|
|
@@ -5145,11 +5119,11 @@ var ContextEngine = class _ContextEngine {
|
|
|
5145
5119
|
* ```
|
|
5146
5120
|
*/
|
|
5147
5121
|
async btw() {
|
|
5148
|
-
await this.#
|
|
5149
|
-
if (!
|
|
5122
|
+
const open = await this.#open();
|
|
5123
|
+
if (!open.branch.headMessageId) {
|
|
5150
5124
|
throw new Error("Cannot create btw branch: no messages in conversation");
|
|
5151
5125
|
}
|
|
5152
|
-
return this.#createBranchFrom(
|
|
5126
|
+
return this.#createBranchFrom(open, open.branch.headMessageId, false);
|
|
5153
5127
|
}
|
|
5154
5128
|
/**
|
|
5155
5129
|
* Update metadata for the current chat.
|
|
@@ -5165,14 +5139,11 @@ var ContextEngine = class _ContextEngine {
|
|
|
5165
5139
|
* ```
|
|
5166
5140
|
*/
|
|
5167
5141
|
async updateChat(updates) {
|
|
5168
|
-
await this.#
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
metadata: updates.metadata === void 0 ? void 0 : { ...metadata, ...updates.metadata }
|
|
5174
|
-
})
|
|
5175
|
-
);
|
|
5142
|
+
const open = await this.#open();
|
|
5143
|
+
open.chat = await this.#store.updateChat(this.#chatId, ({ metadata }) => ({
|
|
5144
|
+
title: updates.title,
|
|
5145
|
+
metadata: updates.metadata === void 0 ? void 0 : { ...metadata, ...updates.metadata }
|
|
5146
|
+
}));
|
|
5176
5147
|
}
|
|
5177
5148
|
/**
|
|
5178
5149
|
* Track token usage for the current chat.
|
|
@@ -5188,20 +5159,17 @@ var ContextEngine = class _ContextEngine {
|
|
|
5188
5159
|
* ```
|
|
5189
5160
|
*/
|
|
5190
5161
|
async trackUsage(usage) {
|
|
5191
|
-
await this.#
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
};
|
|
5203
|
-
}
|
|
5204
|
-
);
|
|
5162
|
+
const open = await this.#open();
|
|
5163
|
+
open.chat = await this.#store.updateChat(this.#chatId, ({ metadata }) => {
|
|
5164
|
+
const storedUsage = metadata?.usage;
|
|
5165
|
+
const currentUsage = isLanguageModelUsage(storedUsage) ? storedUsage : void 0;
|
|
5166
|
+
return {
|
|
5167
|
+
metadata: {
|
|
5168
|
+
...metadata,
|
|
5169
|
+
usage: mergeLanguageModelUsage(currentUsage, usage)
|
|
5170
|
+
}
|
|
5171
|
+
};
|
|
5172
|
+
});
|
|
5205
5173
|
}
|
|
5206
5174
|
/**
|
|
5207
5175
|
* Consolidate context fragments (no-op for now).
|
|
@@ -5267,7 +5235,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
5267
5235
|
* ```
|
|
5268
5236
|
*/
|
|
5269
5237
|
async inspect(options) {
|
|
5270
|
-
await this.#
|
|
5238
|
+
const open = await this.#open();
|
|
5271
5239
|
const { renderer } = options;
|
|
5272
5240
|
const estimateResult = await this.estimate(options.modelId, {
|
|
5273
5241
|
renderer,
|
|
@@ -5276,9 +5244,9 @@ var ContextEngine = class _ContextEngine {
|
|
|
5276
5244
|
});
|
|
5277
5245
|
const rendered = renderer.render(this.#renderableFragments);
|
|
5278
5246
|
const persistedMessages = [];
|
|
5279
|
-
if (
|
|
5247
|
+
if (open.branch.headMessageId) {
|
|
5280
5248
|
const chain = await this.#store.getMessageChain(
|
|
5281
|
-
|
|
5249
|
+
open.branch.headMessageId
|
|
5282
5250
|
);
|
|
5283
5251
|
persistedMessages.push(...chain);
|
|
5284
5252
|
}
|
|
@@ -5294,7 +5262,7 @@ var ContextEngine = class _ContextEngine {
|
|
|
5294
5262
|
graph,
|
|
5295
5263
|
meta: {
|
|
5296
5264
|
chatId: this.#chatId,
|
|
5297
|
-
branch:
|
|
5265
|
+
branch: open.branch.name,
|
|
5298
5266
|
timestamp: Date.now()
|
|
5299
5267
|
}
|
|
5300
5268
|
};
|
|
@@ -10740,7 +10708,7 @@ async function assertMicrosandboxBash(vm) {
|
|
|
10740
10708
|
function normalizeMicrosandboxError(error, sdk) {
|
|
10741
10709
|
const err = toError2(error);
|
|
10742
10710
|
if (err instanceof MicrosandboxSandboxError) return err;
|
|
10743
|
-
if (err instanceof sdk.LibkrunfwNotFoundError) {
|
|
10711
|
+
if (err instanceof sdk.LibkrunfwNotFoundError || err instanceof sdk.RuntimeNotInstalledError || err instanceof sdk.RuntimeIncompleteError) {
|
|
10744
10712
|
return new MicrosandboxNotAvailableError(err);
|
|
10745
10713
|
}
|
|
10746
10714
|
if (err instanceof sdk.MicrosandboxError) {
|
|
@@ -11458,7 +11426,6 @@ var PostgresContextStore = class _PostgresContextStore extends ContextStore {
|
|
|
11458
11426
|
#pool;
|
|
11459
11427
|
#schema;
|
|
11460
11428
|
#ownsPool;
|
|
11461
|
-
#isInitialized = false;
|
|
11462
11429
|
constructor(options) {
|
|
11463
11430
|
super();
|
|
11464
11431
|
const schema = options.schema ?? "public";
|
|
@@ -11488,24 +11455,26 @@ var PostgresContextStore = class _PostgresContextStore extends ContextStore {
|
|
|
11488
11455
|
#t(name) {
|
|
11489
11456
|
return `"${this.#schema}"."${name}"`;
|
|
11490
11457
|
}
|
|
11491
|
-
|
|
11458
|
+
/** Opens the store: creates its schema objects before it returns. */
|
|
11459
|
+
static async create(options) {
|
|
11460
|
+
const store = new _PostgresContextStore(options);
|
|
11461
|
+
try {
|
|
11462
|
+
await store.#initialize();
|
|
11463
|
+
} catch (error) {
|
|
11464
|
+
await store.close();
|
|
11465
|
+
throw error;
|
|
11466
|
+
}
|
|
11467
|
+
return store;
|
|
11468
|
+
}
|
|
11469
|
+
async #initialize() {
|
|
11492
11470
|
const ddl = storeDDL(this.#schema);
|
|
11493
11471
|
await this.#pool.query(ddl);
|
|
11494
|
-
this.#isInitialized = true;
|
|
11495
|
-
}
|
|
11496
|
-
#ensureInitialized() {
|
|
11497
|
-
if (!this.#isInitialized) {
|
|
11498
|
-
throw new Error(
|
|
11499
|
-
"PostgresContextStore not initialized. Call await store.initialize() after construction."
|
|
11500
|
-
);
|
|
11501
|
-
}
|
|
11502
11472
|
}
|
|
11503
11473
|
/**
|
|
11504
11474
|
* Execute a function within a transaction.
|
|
11505
11475
|
* Automatically commits on success or rolls back on error.
|
|
11506
11476
|
*/
|
|
11507
11477
|
async #useTransaction(fn) {
|
|
11508
|
-
this.#ensureInitialized();
|
|
11509
11478
|
const client = await this.#pool.connect();
|
|
11510
11479
|
try {
|
|
11511
11480
|
await client.query("BEGIN");
|
|
@@ -11523,7 +11492,6 @@ var PostgresContextStore = class _PostgresContextStore extends ContextStore {
|
|
|
11523
11492
|
* Execute a query using the pool (no transaction).
|
|
11524
11493
|
*/
|
|
11525
11494
|
async #query(sql, params) {
|
|
11526
|
-
this.#ensureInitialized();
|
|
11527
11495
|
const result = await this.#pool.query(sql, params);
|
|
11528
11496
|
return result.rows;
|
|
11529
11497
|
}
|
|
@@ -12072,6 +12040,11 @@ IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'idx_${schema}_branches_ch
|
|
|
12072
12040
|
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'idx_${schema}_branches_chatId_isActive' AND object_id = OBJECT_ID('[${schema}].[branches]'))
|
|
12073
12041
|
CREATE INDEX [idx_${schema}_branches_chatId_isActive] ON [${schema}].[branches](chatId, isActive);
|
|
12074
12042
|
|
|
12043
|
+
-- Deleting a message checks this foreign key. Without the index the check
|
|
12044
|
+
-- scans every chat's branches and waits on rows another chat delete holds.
|
|
12045
|
+
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'idx_${schema}_branches_headMessageId' AND object_id = OBJECT_ID('[${schema}].[branches]'))
|
|
12046
|
+
CREATE INDEX [idx_${schema}_branches_headMessageId] ON [${schema}].[branches](headMessageId);
|
|
12047
|
+
|
|
12075
12048
|
IF OBJECT_ID('[${schema}].[checkpoints]', 'U') IS NULL
|
|
12076
12049
|
BEGIN
|
|
12077
12050
|
CREATE TABLE [${schema}].[checkpoints] (
|
|
@@ -12225,7 +12198,6 @@ var SqlServerContextStore = class _SqlServerContextStore extends ContextStore {
|
|
|
12225
12198
|
#pool;
|
|
12226
12199
|
#schema;
|
|
12227
12200
|
#ownsPool;
|
|
12228
|
-
#isInitialized = false;
|
|
12229
12201
|
constructor(options) {
|
|
12230
12202
|
super();
|
|
12231
12203
|
const schema = options.schema ?? "dbo";
|
|
@@ -12255,7 +12227,18 @@ var SqlServerContextStore = class _SqlServerContextStore extends ContextStore {
|
|
|
12255
12227
|
#t(name) {
|
|
12256
12228
|
return `[${this.#schema}].[${name}]`;
|
|
12257
12229
|
}
|
|
12258
|
-
|
|
12230
|
+
/** Opens the store: connects a pool it owns and creates its schema objects before it returns. */
|
|
12231
|
+
static async create(options) {
|
|
12232
|
+
const store = new _SqlServerContextStore(options);
|
|
12233
|
+
try {
|
|
12234
|
+
await store.#initialize();
|
|
12235
|
+
} catch (error) {
|
|
12236
|
+
await store.close();
|
|
12237
|
+
throw error;
|
|
12238
|
+
}
|
|
12239
|
+
return store;
|
|
12240
|
+
}
|
|
12241
|
+
async #initialize() {
|
|
12259
12242
|
if (this.#ownsPool) {
|
|
12260
12243
|
await this.#pool.connect();
|
|
12261
12244
|
}
|
|
@@ -12275,21 +12258,12 @@ var SqlServerContextStore = class _SqlServerContextStore extends ContextStore {
|
|
|
12275
12258
|
await this.#pool.request().batch(batch);
|
|
12276
12259
|
}
|
|
12277
12260
|
}
|
|
12278
|
-
this.#isInitialized = true;
|
|
12279
|
-
}
|
|
12280
|
-
#ensureInitialized() {
|
|
12281
|
-
if (!this.#isInitialized) {
|
|
12282
|
-
throw new Error(
|
|
12283
|
-
"SqlServerContextStore not initialized. Call await store.initialize() after construction."
|
|
12284
|
-
);
|
|
12285
|
-
}
|
|
12286
12261
|
}
|
|
12287
12262
|
/**
|
|
12288
12263
|
* Execute a function within a transaction.
|
|
12289
12264
|
* Automatically commits on success or rolls back on error.
|
|
12290
12265
|
*/
|
|
12291
12266
|
async #useTransaction(fn) {
|
|
12292
|
-
this.#ensureInitialized();
|
|
12293
12267
|
const mssql = _SqlServerContextStore.#requireMssql();
|
|
12294
12268
|
const transaction = new mssql.Transaction(this.#pool);
|
|
12295
12269
|
try {
|
|
@@ -12307,7 +12281,6 @@ var SqlServerContextStore = class _SqlServerContextStore extends ContextStore {
|
|
|
12307
12281
|
* Converts positional params to SQL Server named params (@p0, @p1, ...).
|
|
12308
12282
|
*/
|
|
12309
12283
|
async #query(sql, params) {
|
|
12310
|
-
this.#ensureInitialized();
|
|
12311
12284
|
const request = this.#pool.request();
|
|
12312
12285
|
params?.forEach((value, index) => {
|
|
12313
12286
|
request.input(`p${index}`, value);
|
|
@@ -13159,7 +13132,9 @@ function staticPartText(part, options) {
|
|
|
13159
13132
|
}
|
|
13160
13133
|
|
|
13161
13134
|
// packages/context/src/lib/stream/postgres-notify-change-source.ts
|
|
13135
|
+
import { EventEmitter, on } from "node:events";
|
|
13162
13136
|
import { createRequire as createRequire3 } from "node:module";
|
|
13137
|
+
import pMemoize3 from "p-memoize";
|
|
13163
13138
|
import { z as z16 } from "zod";
|
|
13164
13139
|
|
|
13165
13140
|
// packages/context/src/lib/stream/ddl.stream.postgres-notify.ts
|
|
@@ -13220,28 +13195,73 @@ EXECUTE FUNCTION "${schema}"."notify_stream_status_update"();
|
|
|
13220
13195
|
}
|
|
13221
13196
|
|
|
13222
13197
|
// packages/context/src/lib/stream/postgres-notify-change-source.ts
|
|
13198
|
+
var NOT_LISTENING = {
|
|
13199
|
+
release: () => Promise.resolve(),
|
|
13200
|
+
fail: () => {
|
|
13201
|
+
}
|
|
13202
|
+
};
|
|
13203
|
+
var Listening = class {
|
|
13204
|
+
#client;
|
|
13205
|
+
#handlers;
|
|
13206
|
+
constructor(client, handlers) {
|
|
13207
|
+
this.#client = client;
|
|
13208
|
+
this.#handlers = handlers;
|
|
13209
|
+
client.on("notification", handlers.notification);
|
|
13210
|
+
client.on("error", handlers.error);
|
|
13211
|
+
client.on("end", handlers.end);
|
|
13212
|
+
}
|
|
13213
|
+
/** Stops listening and returns the connection to the pool. */
|
|
13214
|
+
async release(channel) {
|
|
13215
|
+
this.#detach();
|
|
13216
|
+
try {
|
|
13217
|
+
await this.#client.query(`UNLISTEN ${quoteIdentifier(channel)}`);
|
|
13218
|
+
} finally {
|
|
13219
|
+
this.#client.release();
|
|
13220
|
+
}
|
|
13221
|
+
}
|
|
13222
|
+
/** Gives a broken connection back for the pool to destroy. */
|
|
13223
|
+
fail(error) {
|
|
13224
|
+
this.#detach();
|
|
13225
|
+
this.#client.release(error);
|
|
13226
|
+
}
|
|
13227
|
+
#detach() {
|
|
13228
|
+
this.#client.off("notification", this.#handlers.notification);
|
|
13229
|
+
this.#client.off("error", this.#handlers.error);
|
|
13230
|
+
this.#client.off("end", this.#handlers.end);
|
|
13231
|
+
}
|
|
13232
|
+
};
|
|
13233
|
+
var ChangeDelivery = class {
|
|
13234
|
+
change;
|
|
13235
|
+
constructor(change) {
|
|
13236
|
+
this.change = change;
|
|
13237
|
+
}
|
|
13238
|
+
};
|
|
13223
13239
|
var PostgresNotifyChangeSource = class _PostgresNotifyChangeSource {
|
|
13224
13240
|
#pool;
|
|
13225
13241
|
#schema;
|
|
13226
13242
|
#channel;
|
|
13227
13243
|
#ownsPool;
|
|
13228
|
-
|
|
13229
|
-
#
|
|
13230
|
-
|
|
13231
|
-
#
|
|
13232
|
-
#
|
|
13233
|
-
#
|
|
13234
|
-
|
|
13235
|
-
|
|
13236
|
-
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
|
|
13240
|
-
|
|
13241
|
-
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
)
|
|
13244
|
+
/** Aborts when close() starts: every subscription ends, and no LISTEN connection opens. */
|
|
13245
|
+
#closed = new AbortController();
|
|
13246
|
+
/** Emits `stream:<id>` with a ChangeDelivery; `error` fails every subscription. */
|
|
13247
|
+
#changes = new EventEmitter().setMaxListeners(0);
|
|
13248
|
+
#subscriptions = 0;
|
|
13249
|
+
#listener = NOT_LISTENING;
|
|
13250
|
+
/** Concurrent subscribers share one LISTEN setup; a failed one runs again. */
|
|
13251
|
+
#listen = pMemoize3(() => this.#openListener(), { cache: false });
|
|
13252
|
+
#handlers = {
|
|
13253
|
+
notification: (message2) => {
|
|
13254
|
+
this.#handleNotification(message2);
|
|
13255
|
+
},
|
|
13256
|
+
error: (error) => {
|
|
13257
|
+
this.#failListener(error);
|
|
13258
|
+
},
|
|
13259
|
+
end: () => {
|
|
13260
|
+
if (!this.#closed.signal.aborted) {
|
|
13261
|
+
this.#failListener(
|
|
13262
|
+
new Error("PostgreSQL stream notification listener ended")
|
|
13263
|
+
);
|
|
13264
|
+
}
|
|
13245
13265
|
}
|
|
13246
13266
|
};
|
|
13247
13267
|
constructor(options) {
|
|
@@ -13270,98 +13290,75 @@ var PostgresNotifyChangeSource = class _PostgresNotifyChangeSource {
|
|
|
13270
13290
|
);
|
|
13271
13291
|
}
|
|
13272
13292
|
}
|
|
13273
|
-
|
|
13274
|
-
|
|
13275
|
-
|
|
13276
|
-
|
|
13277
|
-
|
|
13293
|
+
/** Opens the source: installs the notify triggers before it returns. */
|
|
13294
|
+
static async create(options) {
|
|
13295
|
+
const source = new _PostgresNotifyChangeSource(options);
|
|
13296
|
+
try {
|
|
13297
|
+
await source.#pool.query(
|
|
13298
|
+
postgresStreamNotifyDDL(source.#schema, source.#channel)
|
|
13299
|
+
);
|
|
13300
|
+
} catch (error) {
|
|
13301
|
+
await source.close();
|
|
13302
|
+
throw error;
|
|
13303
|
+
}
|
|
13304
|
+
return source;
|
|
13278
13305
|
}
|
|
13279
13306
|
async *subscribe(streamId, signal) {
|
|
13280
|
-
this.#
|
|
13281
|
-
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
const
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
signal.addEventListener("abort", cleanup, { once: true });
|
|
13307
|
+
if (this.#closed.signal.aborted) {
|
|
13308
|
+
throw new Error("PostgresNotifyChangeSource is closed.");
|
|
13309
|
+
}
|
|
13310
|
+
if (signal.aborted) return;
|
|
13311
|
+
const changes = on(this.#changes, `stream:${streamId}`, {
|
|
13312
|
+
signal: AbortSignal.any([signal, this.#closed.signal])
|
|
13313
|
+
});
|
|
13314
|
+
this.#subscriptions += 1;
|
|
13289
13315
|
try {
|
|
13290
13316
|
await this.#ensureListening();
|
|
13291
|
-
if (signal.aborted || this.#
|
|
13317
|
+
if (signal.aborted || this.#closed.signal.aborted) return;
|
|
13292
13318
|
yield { kind: "tick" };
|
|
13293
|
-
|
|
13294
|
-
|
|
13295
|
-
if (!change) return;
|
|
13296
|
-
yield change;
|
|
13319
|
+
for await (const [delivery] of changes) {
|
|
13320
|
+
if (delivery instanceof ChangeDelivery) yield delivery.change;
|
|
13297
13321
|
}
|
|
13322
|
+
} catch (error) {
|
|
13323
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
13324
|
+
throw error;
|
|
13298
13325
|
} finally {
|
|
13299
|
-
|
|
13300
|
-
|
|
13326
|
+
this.#subscriptions -= 1;
|
|
13327
|
+
await changes.return?.();
|
|
13301
13328
|
await this.#releaseListenerIfIdle();
|
|
13302
13329
|
}
|
|
13303
13330
|
}
|
|
13304
13331
|
async close() {
|
|
13305
|
-
if (this.#
|
|
13306
|
-
this.#
|
|
13307
|
-
|
|
13308
|
-
|
|
13309
|
-
|
|
13310
|
-
subscriber.close();
|
|
13311
|
-
}
|
|
13312
|
-
}
|
|
13313
|
-
this.#subscribers.clear();
|
|
13314
|
-
if (this.#listenPromise) {
|
|
13315
|
-
try {
|
|
13316
|
-
await this.#listenPromise;
|
|
13317
|
-
} catch {
|
|
13318
|
-
}
|
|
13332
|
+
if (this.#closed.signal.aborted) return;
|
|
13333
|
+
this.#closed.abort();
|
|
13334
|
+
try {
|
|
13335
|
+
await this.#listen();
|
|
13336
|
+
} catch {
|
|
13319
13337
|
}
|
|
13320
13338
|
await this.#releaseListener();
|
|
13321
13339
|
if (this.#ownsPool) {
|
|
13322
13340
|
await this.#pool.end();
|
|
13323
13341
|
}
|
|
13324
13342
|
}
|
|
13325
|
-
#
|
|
13326
|
-
if (
|
|
13327
|
-
|
|
13328
|
-
"PostgresNotifyChangeSource not initialized. Call await source.initialize() after construction."
|
|
13329
|
-
);
|
|
13330
|
-
}
|
|
13343
|
+
async #ensureListening() {
|
|
13344
|
+
if (this.#listener instanceof Listening) return;
|
|
13345
|
+
await this.#listen();
|
|
13331
13346
|
}
|
|
13332
|
-
#
|
|
13333
|
-
if (this.#
|
|
13334
|
-
|
|
13347
|
+
async #openListener() {
|
|
13348
|
+
if (this.#closed.signal.aborted) return;
|
|
13349
|
+
const client = await this.#pool.connect();
|
|
13350
|
+
const listening = new Listening(client, this.#handlers);
|
|
13351
|
+
try {
|
|
13352
|
+
await client.query(`LISTEN ${quoteIdentifier(this.#channel)}`);
|
|
13353
|
+
} catch (error) {
|
|
13354
|
+
listening.fail(true);
|
|
13355
|
+
throw error;
|
|
13335
13356
|
}
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
|
|
13341
|
-
this.#listenPromise = (async () => {
|
|
13342
|
-
const listener = await this.#pool.connect();
|
|
13343
|
-
let success = false;
|
|
13344
|
-
try {
|
|
13345
|
-
listener.on("notification", this.#onNotification);
|
|
13346
|
-
listener.on("error", this.#onListenerError);
|
|
13347
|
-
listener.on("end", this.#onListenerEnd);
|
|
13348
|
-
await listener.query(`LISTEN ${quoteIdentifier(this.#channel)}`);
|
|
13349
|
-
if (this.#isClosed) {
|
|
13350
|
-
return;
|
|
13351
|
-
}
|
|
13352
|
-
this.#listener = listener;
|
|
13353
|
-
success = true;
|
|
13354
|
-
} finally {
|
|
13355
|
-
this.#listenPromise = void 0;
|
|
13356
|
-
if (!success) {
|
|
13357
|
-
listener.off("notification", this.#onNotification);
|
|
13358
|
-
listener.off("error", this.#onListenerError);
|
|
13359
|
-
listener.off("end", this.#onListenerEnd);
|
|
13360
|
-
listener.release(true);
|
|
13361
|
-
}
|
|
13362
|
-
}
|
|
13363
|
-
})();
|
|
13364
|
-
return this.#listenPromise;
|
|
13357
|
+
if (this.#closed.signal.aborted) {
|
|
13358
|
+
listening.fail(true);
|
|
13359
|
+
return;
|
|
13360
|
+
}
|
|
13361
|
+
this.#listener = listening;
|
|
13365
13362
|
}
|
|
13366
13363
|
#handleNotification(message2) {
|
|
13367
13364
|
if (message2.channel !== this.#channel || !message2.payload) return;
|
|
@@ -13369,125 +13366,28 @@ var PostgresNotifyChangeSource = class _PostgresNotifyChangeSource {
|
|
|
13369
13366
|
if (!payload) return;
|
|
13370
13367
|
if (payload.schema !== this.#schema) return;
|
|
13371
13368
|
if (payload.kind !== "chunks" && payload.kind !== "status") return;
|
|
13372
|
-
const subscribers = this.#subscribers.get(payload.streamId);
|
|
13373
|
-
if (!subscribers) return;
|
|
13374
13369
|
const change = payload.kind === "chunks" ? { kind: "chunks" } : { kind: "status" };
|
|
13375
|
-
|
|
13376
|
-
|
|
13377
|
-
|
|
13370
|
+
this.#changes.emit(
|
|
13371
|
+
`stream:${payload.streamId}`,
|
|
13372
|
+
new ChangeDelivery(change)
|
|
13373
|
+
);
|
|
13378
13374
|
}
|
|
13379
13375
|
#failListener(error) {
|
|
13380
13376
|
const listener = this.#listener;
|
|
13381
|
-
this.#listener =
|
|
13382
|
-
|
|
13383
|
-
if (
|
|
13384
|
-
|
|
13385
|
-
listener.off("error", this.#onListenerError);
|
|
13386
|
-
listener.off("end", this.#onListenerEnd);
|
|
13387
|
-
listener.release(error);
|
|
13388
|
-
}
|
|
13389
|
-
for (const subscribers of this.#subscribers.values()) {
|
|
13390
|
-
for (const subscriber of subscribers) {
|
|
13391
|
-
subscriber.fail(error);
|
|
13392
|
-
}
|
|
13377
|
+
this.#listener = NOT_LISTENING;
|
|
13378
|
+
listener.fail(error);
|
|
13379
|
+
if (this.#changes.listenerCount("error") > 0) {
|
|
13380
|
+
this.#changes.emit("error", error);
|
|
13393
13381
|
}
|
|
13394
|
-
this.#subscribers.clear();
|
|
13395
13382
|
}
|
|
13396
13383
|
async #releaseListenerIfIdle() {
|
|
13397
|
-
if (this.#
|
|
13384
|
+
if (this.#subscriptions > 0) return;
|
|
13398
13385
|
await this.#releaseListener();
|
|
13399
13386
|
}
|
|
13400
13387
|
async #releaseListener() {
|
|
13401
13388
|
const listener = this.#listener;
|
|
13402
|
-
|
|
13403
|
-
this.#
|
|
13404
|
-
listener.off("notification", this.#onNotification);
|
|
13405
|
-
listener.off("error", this.#onListenerError);
|
|
13406
|
-
listener.off("end", this.#onListenerEnd);
|
|
13407
|
-
try {
|
|
13408
|
-
await listener.query(`UNLISTEN ${quoteIdentifier(this.#channel)}`);
|
|
13409
|
-
} finally {
|
|
13410
|
-
listener.release();
|
|
13411
|
-
}
|
|
13412
|
-
}
|
|
13413
|
-
#addSubscriber(streamId, subscriber) {
|
|
13414
|
-
let subscribers = this.#subscribers.get(streamId);
|
|
13415
|
-
if (!subscribers) {
|
|
13416
|
-
subscribers = /* @__PURE__ */ new Set();
|
|
13417
|
-
this.#subscribers.set(streamId, subscribers);
|
|
13418
|
-
}
|
|
13419
|
-
subscribers.add(subscriber);
|
|
13420
|
-
}
|
|
13421
|
-
#removeSubscriber(streamId, subscriber) {
|
|
13422
|
-
const subscribers = this.#subscribers.get(streamId);
|
|
13423
|
-
if (!subscribers) return;
|
|
13424
|
-
subscribers.delete(subscriber);
|
|
13425
|
-
if (subscribers.size === 0) {
|
|
13426
|
-
this.#subscribers.delete(streamId);
|
|
13427
|
-
}
|
|
13428
|
-
}
|
|
13429
|
-
};
|
|
13430
|
-
var ChangeQueue = class {
|
|
13431
|
-
#values = [];
|
|
13432
|
-
#waiters = /* @__PURE__ */ new Set();
|
|
13433
|
-
#closed = false;
|
|
13434
|
-
#error;
|
|
13435
|
-
push(value) {
|
|
13436
|
-
if (this.#closed) return;
|
|
13437
|
-
const waiter = this.#waiters.values().next().value;
|
|
13438
|
-
if (waiter) {
|
|
13439
|
-
this.#waiters.delete(waiter);
|
|
13440
|
-
waiter.resolve(value);
|
|
13441
|
-
return;
|
|
13442
|
-
}
|
|
13443
|
-
this.#values.push(value);
|
|
13444
|
-
}
|
|
13445
|
-
fail(error) {
|
|
13446
|
-
if (this.#closed) return;
|
|
13447
|
-
this.#closed = true;
|
|
13448
|
-
this.#error = error;
|
|
13449
|
-
this.#values = [];
|
|
13450
|
-
for (const waiter of this.#waiters) {
|
|
13451
|
-
waiter.reject(error);
|
|
13452
|
-
}
|
|
13453
|
-
this.#waiters.clear();
|
|
13454
|
-
}
|
|
13455
|
-
close() {
|
|
13456
|
-
if (this.#closed) return;
|
|
13457
|
-
this.#closed = true;
|
|
13458
|
-
this.#values = [];
|
|
13459
|
-
for (const waiter of this.#waiters) {
|
|
13460
|
-
waiter.resolve(void 0);
|
|
13461
|
-
}
|
|
13462
|
-
this.#waiters.clear();
|
|
13463
|
-
}
|
|
13464
|
-
async next(signal) {
|
|
13465
|
-
if (this.#error) throw this.#error;
|
|
13466
|
-
if (this.#closed || signal.aborted) return void 0;
|
|
13467
|
-
if (this.#values.length > 0) {
|
|
13468
|
-
return this.#values.shift();
|
|
13469
|
-
}
|
|
13470
|
-
return new Promise((resolve3, reject) => {
|
|
13471
|
-
const waiter = { resolve: resolve3, reject };
|
|
13472
|
-
const cleanup = () => {
|
|
13473
|
-
this.#waiters.delete(waiter);
|
|
13474
|
-
signal.removeEventListener("abort", onAbort);
|
|
13475
|
-
};
|
|
13476
|
-
const onAbort = () => {
|
|
13477
|
-
cleanup();
|
|
13478
|
-
resolve3(void 0);
|
|
13479
|
-
};
|
|
13480
|
-
waiter.resolve = (value) => {
|
|
13481
|
-
cleanup();
|
|
13482
|
-
resolve3(value);
|
|
13483
|
-
};
|
|
13484
|
-
waiter.reject = (error) => {
|
|
13485
|
-
cleanup();
|
|
13486
|
-
reject(error);
|
|
13487
|
-
};
|
|
13488
|
-
this.#waiters.add(waiter);
|
|
13489
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
13490
|
-
});
|
|
13389
|
+
this.#listener = NOT_LISTENING;
|
|
13390
|
+
await listener.release(this.#channel);
|
|
13491
13391
|
}
|
|
13492
13392
|
};
|
|
13493
13393
|
var notificationPayload = z16.object({
|
|
@@ -13610,8 +13510,6 @@ var PostgresStreamStore = class _PostgresStreamStore extends StreamStore {
|
|
|
13610
13510
|
#pool;
|
|
13611
13511
|
#schema;
|
|
13612
13512
|
#ownsPool;
|
|
13613
|
-
#isInitialized = false;
|
|
13614
|
-
#isClosed = false;
|
|
13615
13513
|
constructor(options) {
|
|
13616
13514
|
super();
|
|
13617
13515
|
const schema = options.schema ?? "public";
|
|
@@ -13639,26 +13537,26 @@ var PostgresStreamStore = class _PostgresStreamStore extends StreamStore {
|
|
|
13639
13537
|
#t(name) {
|
|
13640
13538
|
return `"${this.#schema}"."${name}"`;
|
|
13641
13539
|
}
|
|
13642
|
-
|
|
13540
|
+
/** Opens the store: creates its tables before it returns. */
|
|
13541
|
+
static async create(options) {
|
|
13542
|
+
const store = new _PostgresStreamStore(options);
|
|
13543
|
+
try {
|
|
13544
|
+
await store.#initialize();
|
|
13545
|
+
} catch (error) {
|
|
13546
|
+
await store.close();
|
|
13547
|
+
throw error;
|
|
13548
|
+
}
|
|
13549
|
+
return store;
|
|
13550
|
+
}
|
|
13551
|
+
async #initialize() {
|
|
13643
13552
|
await this.#pool.query(postgresStreamDDL(this.#schema));
|
|
13644
|
-
this.#isInitialized = true;
|
|
13645
13553
|
}
|
|
13646
13554
|
async close() {
|
|
13647
|
-
if (this.#
|
|
13648
|
-
this.#isClosed = true;
|
|
13649
|
-
if (this.#ownsPool) {
|
|
13555
|
+
if (this.#ownsPool && !this.#pool.ending) {
|
|
13650
13556
|
await this.#pool.end();
|
|
13651
13557
|
}
|
|
13652
13558
|
}
|
|
13653
|
-
#ensureInitialized() {
|
|
13654
|
-
if (!this.#isInitialized) {
|
|
13655
|
-
throw new Error(
|
|
13656
|
-
"PostgresStreamStore not initialized. Call await store.initialize() after construction."
|
|
13657
|
-
);
|
|
13658
|
-
}
|
|
13659
|
-
}
|
|
13660
13559
|
async #query(sql, params) {
|
|
13661
|
-
this.#ensureInitialized();
|
|
13662
13560
|
const result = await this.#pool.query(sql, params);
|
|
13663
13561
|
return result.rows;
|
|
13664
13562
|
}
|
|
@@ -13666,7 +13564,6 @@ var PostgresStreamStore = class _PostgresStreamStore extends StreamStore {
|
|
|
13666
13564
|
return z18.array(row).parse(await this.#query(sql, params));
|
|
13667
13565
|
}
|
|
13668
13566
|
async #useTransaction(fn) {
|
|
13669
|
-
this.#ensureInitialized();
|
|
13670
13567
|
const client = await this.#pool.connect();
|
|
13671
13568
|
try {
|
|
13672
13569
|
await client.query("BEGIN");
|
|
@@ -13949,7 +13846,7 @@ import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
|
13949
13846
|
import { z as z19 } from "zod";
|
|
13950
13847
|
|
|
13951
13848
|
// packages/context/src/lib/stream/ddl.stream.sqlite.sql
|
|
13952
|
-
var ddl_stream_sqlite_default = "PRAGMA journal_mode = WAL;\nPRAGMA synchronous = NORMAL;\nPRAGMA foreign_keys = ON;\n\nCREATE TABLE IF NOT EXISTS streams (\n id TEXT PRIMARY KEY,\n status TEXT NOT NULL DEFAULT 'queued'\n CHECK(status IN ('queued','running','completed','failed','cancelled')),\n createdAt INTEGER NOT NULL,\n startedAt INTEGER,\n finishedAt INTEGER,\n cancelRequestedAt INTEGER,\n error TEXT\n);\n\nCREATE TABLE IF NOT EXISTS stream_chunks (\n streamId TEXT NOT NULL,\n seq INTEGER NOT NULL,\n data TEXT NOT NULL,\n createdAt INTEGER NOT NULL,\n PRIMARY KEY (streamId, seq),\n FOREIGN KEY (streamId) REFERENCES streams(id) ON DELETE CASCADE\n);\n\n-- Supports ordered listing across all streams.\nCREATE INDEX IF NOT EXISTS idx_streams_created_at_id\n ON streams(createdAt, id);\n\n-- Supports status-filtered ordered listing (e.g. running streams).\nCREATE INDEX IF NOT EXISTS idx_streams_status_created_at_id\n ON streams(status, createdAt, id);\n";
|
|
13849
|
+
var ddl_stream_sqlite_default = "PRAGMA busy_timeout = 5000;\nPRAGMA journal_mode = WAL;\nPRAGMA synchronous = NORMAL;\nPRAGMA foreign_keys = ON;\n\nCREATE TABLE IF NOT EXISTS streams (\n id TEXT PRIMARY KEY,\n status TEXT NOT NULL DEFAULT 'queued'\n CHECK(status IN ('queued','running','completed','failed','cancelled')),\n createdAt INTEGER NOT NULL,\n startedAt INTEGER,\n finishedAt INTEGER,\n cancelRequestedAt INTEGER,\n error TEXT\n);\n\nCREATE TABLE IF NOT EXISTS stream_chunks (\n streamId TEXT NOT NULL,\n seq INTEGER NOT NULL,\n data TEXT NOT NULL,\n createdAt INTEGER NOT NULL,\n PRIMARY KEY (streamId, seq),\n FOREIGN KEY (streamId) REFERENCES streams(id) ON DELETE CASCADE\n);\n\n-- Supports ordered listing across all streams.\nCREATE INDEX IF NOT EXISTS idx_streams_created_at_id\n ON streams(createdAt, id);\n\n-- Supports status-filtered ordered listing (e.g. running streams).\nCREATE INDEX IF NOT EXISTS idx_streams_status_created_at_id\n ON streams(status, createdAt, id);\n";
|
|
13953
13850
|
|
|
13954
13851
|
// packages/context/src/lib/stream/sqlite.stream-store.ts
|
|
13955
13852
|
var streamRow = z19.object({
|
|
@@ -13972,7 +13869,6 @@ var chunkRow2 = z19.object({
|
|
|
13972
13869
|
var SqliteStreamStore = class extends StreamStore {
|
|
13973
13870
|
#db;
|
|
13974
13871
|
#statements = /* @__PURE__ */ new Map();
|
|
13975
|
-
#closed = false;
|
|
13976
13872
|
#stmt(sql) {
|
|
13977
13873
|
let stmt = this.#statements.get(sql);
|
|
13978
13874
|
if (!stmt) {
|
|
@@ -13982,8 +13878,7 @@ var SqliteStreamStore = class extends StreamStore {
|
|
|
13982
13878
|
return stmt;
|
|
13983
13879
|
}
|
|
13984
13880
|
close() {
|
|
13985
|
-
if (this.#
|
|
13986
|
-
this.#closed = true;
|
|
13881
|
+
if (!this.#db.isOpen) return;
|
|
13987
13882
|
this.#statements.clear();
|
|
13988
13883
|
this.#db.close();
|
|
13989
13884
|
}
|
|
@@ -14124,8 +14019,7 @@ var SqliteStreamStore = class extends StreamStore {
|
|
|
14124
14019
|
async appendChunks(chunks) {
|
|
14125
14020
|
if (chunks.length === 0) return;
|
|
14126
14021
|
const failures = collectStreamFailures(chunks);
|
|
14127
|
-
this.#
|
|
14128
|
-
try {
|
|
14022
|
+
this.#transaction(() => {
|
|
14129
14023
|
for (const chunk of chunks) {
|
|
14130
14024
|
this.#stmt(
|
|
14131
14025
|
`INSERT INTO stream_chunks (streamId, seq, data, createdAt)
|
|
@@ -14152,11 +14046,7 @@ var SqliteStreamStore = class extends StreamStore {
|
|
|
14152
14046
|
}
|
|
14153
14047
|
}
|
|
14154
14048
|
}
|
|
14155
|
-
|
|
14156
|
-
} catch (error) {
|
|
14157
|
-
this.#db.exec("ROLLBACK");
|
|
14158
|
-
throw error;
|
|
14159
|
-
}
|
|
14049
|
+
});
|
|
14160
14050
|
}
|
|
14161
14051
|
async getChunks(streamId, fromSeq, limit) {
|
|
14162
14052
|
let sql = "SELECT * FROM stream_chunks WHERE streamId = ?";
|
|
@@ -14212,13 +14102,16 @@ var SqliteStreamStore = class extends StreamStore {
|
|
|
14212
14102
|
});
|
|
14213
14103
|
}
|
|
14214
14104
|
#transaction(callback) {
|
|
14105
|
+
this.#db.exec("BEGIN IMMEDIATE");
|
|
14215
14106
|
try {
|
|
14216
|
-
this.#db.exec("BEGIN IMMEDIATE");
|
|
14217
14107
|
const result = callback();
|
|
14218
14108
|
this.#db.exec("COMMIT");
|
|
14219
14109
|
return result;
|
|
14220
14110
|
} catch (error) {
|
|
14221
|
-
|
|
14111
|
+
try {
|
|
14112
|
+
this.#db.exec("ROLLBACK");
|
|
14113
|
+
} catch {
|
|
14114
|
+
}
|
|
14222
14115
|
throw error;
|
|
14223
14116
|
}
|
|
14224
14117
|
}
|
|
@@ -14686,7 +14579,6 @@ export {
|
|
|
14686
14579
|
PostgresContextStore,
|
|
14687
14580
|
PostgresNotifyChangeSource,
|
|
14688
14581
|
PostgresStreamStore,
|
|
14689
|
-
PromiseResolver,
|
|
14690
14582
|
RuntimeStrategy,
|
|
14691
14583
|
SqlServerContextStore,
|
|
14692
14584
|
SqliteContextStore,
|