stratagate-dsh 0.2.71 → 0.2.73
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/CHANGELOG.md +11 -0
- package/README.md +324 -213
- package/README.zh-CN.md +326 -213
- package/dist/client.js +3 -3
- package/dist/plugin.js +267 -31
- package/dist/plugin.js.map +1 -1
- package/docs/DSH.md +4 -2
- package/docs/DSH.zh-CN.md +4 -2
- package/docs/assets/41fc676096d0a13337a1c03aaf8f499b.png +0 -0
- package/docs/assets/aaed14b0b43a76334008117f6ca104af.png +0 -0
- package/docs/assets/cecc9d191a4b9bf22a479623e2ebdc1d.png +0 -0
- package/docs/assets/fc07e5b6e1cc07c115faa773a2718aa9.png +0 -0
- package/package.json +25 -24
package/dist/plugin.js
CHANGED
|
@@ -1905,6 +1905,29 @@ CREATE TABLE IF NOT EXISTS external_memory_import_jobs (
|
|
|
1905
1905
|
PRIMARY KEY (namespace, id),
|
|
1906
1906
|
FOREIGN KEY (namespace) REFERENCES memory_spaces(namespace) ON DELETE CASCADE
|
|
1907
1907
|
) STRICT;
|
|
1908
|
+
|
|
1909
|
+
CREATE TABLE IF NOT EXISTS raw_message_fts_meta (
|
|
1910
|
+
namespace TEXT NOT NULL,
|
|
1911
|
+
message_id TEXT NOT NULL,
|
|
1912
|
+
tokens TEXT NOT NULL,
|
|
1913
|
+
fts_rowid INTEGER NOT NULL,
|
|
1914
|
+
PRIMARY KEY (namespace, message_id),
|
|
1915
|
+
FOREIGN KEY (namespace, message_id) REFERENCES messages(namespace, id) ON DELETE CASCADE
|
|
1916
|
+
) STRICT;
|
|
1917
|
+
|
|
1918
|
+
CREATE TABLE IF NOT EXISTS raw_message_fts_state (
|
|
1919
|
+
namespace TEXT PRIMARY KEY,
|
|
1920
|
+
backfill_complete INTEGER NOT NULL DEFAULT 0,
|
|
1921
|
+
FOREIGN KEY (namespace) REFERENCES memory_spaces(namespace) ON DELETE CASCADE
|
|
1922
|
+
) STRICT;
|
|
1923
|
+
`;
|
|
1924
|
+
var RAW_MESSAGE_FTS_SCHEMA = `
|
|
1925
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS raw_message_fts USING fts5(
|
|
1926
|
+
namespace UNINDEXED,
|
|
1927
|
+
message_id UNINDEXED,
|
|
1928
|
+
tokens,
|
|
1929
|
+
tokenize = 'unicode61'
|
|
1930
|
+
);
|
|
1908
1931
|
`;
|
|
1909
1932
|
var THREAD_INDEXES = `
|
|
1910
1933
|
CREATE INDEX IF NOT EXISTS messages_thread_idx ON messages(namespace, thread_id, position);
|
|
@@ -1922,8 +1945,15 @@ function nonEmptyNamespace(namespace) {
|
|
|
1922
1945
|
if (!normalized) throw new TypeError("Storage namespace must not be empty");
|
|
1923
1946
|
return normalized;
|
|
1924
1947
|
}
|
|
1948
|
+
function encodeRawSearchToken(token) {
|
|
1949
|
+
return `t${Buffer.from(token, "utf8").toString("hex")}`;
|
|
1950
|
+
}
|
|
1951
|
+
function encodedRawSearchTokens(content) {
|
|
1952
|
+
return searchTokens(content).map(encodeRawSearchToken).join(" ");
|
|
1953
|
+
}
|
|
1925
1954
|
var SqliteStorage = class {
|
|
1926
1955
|
database;
|
|
1956
|
+
rawSearchFtsAvailable = false;
|
|
1927
1957
|
closed = false;
|
|
1928
1958
|
constructor(options) {
|
|
1929
1959
|
if (!options.filename.trim()) throw new TypeError("SQLite filename must not be empty");
|
|
@@ -2213,21 +2243,46 @@ var SqliteStorage = class {
|
|
|
2213
2243
|
};
|
|
2214
2244
|
return { snapshot: cloneSnapshot(normalizeSnapshot(snapshot)), revision: space.revision };
|
|
2215
2245
|
}
|
|
2216
|
-
async save(namespace, snapshot, expectedRevision) {
|
|
2246
|
+
async save(namespace, snapshot, expectedRevision, rawMessageIndexDelta) {
|
|
2217
2247
|
this.assertOpen();
|
|
2218
2248
|
assertValidSnapshot(snapshot);
|
|
2219
2249
|
if (!Number.isSafeInteger(expectedRevision) || expectedRevision < 0) {
|
|
2220
2250
|
throw new TypeError("expectedRevision must be a non-negative integer");
|
|
2221
2251
|
}
|
|
2222
2252
|
const key = nonEmptyNamespace(namespace);
|
|
2223
|
-
return this.immediateTransaction(() => this.persistSnapshot(key, snapshot, expectedRevision));
|
|
2253
|
+
return this.immediateTransaction(() => this.persistSnapshot(key, snapshot, expectedRevision, rawMessageIndexDelta));
|
|
2224
2254
|
}
|
|
2225
2255
|
async close() {
|
|
2226
2256
|
if (this.closed) return;
|
|
2227
2257
|
this.database.close();
|
|
2228
2258
|
this.closed = true;
|
|
2229
2259
|
}
|
|
2230
|
-
|
|
2260
|
+
searchRawMessageIds(namespace, tokens, limit, threadId, includeUnthreaded = false) {
|
|
2261
|
+
this.assertOpen();
|
|
2262
|
+
if (!this.rawSearchFtsAvailable || tokens.length === 0) return null;
|
|
2263
|
+
const key = nonEmptyNamespace(namespace);
|
|
2264
|
+
const boundedLimit = Math.max(1, Math.min(5e3, Math.floor(limit)));
|
|
2265
|
+
const match = tokens.map(encodeRawSearchToken).filter(Boolean).map((token) => `"${token}"`).join(" OR ");
|
|
2266
|
+
if (!match) return [];
|
|
2267
|
+
try {
|
|
2268
|
+
const rows = this.database.prepare(`
|
|
2269
|
+
SELECT f.message_id
|
|
2270
|
+
FROM raw_message_fts AS f
|
|
2271
|
+
INNER JOIN messages AS m
|
|
2272
|
+
ON m.namespace = f.namespace AND m.id = f.message_id
|
|
2273
|
+
WHERE raw_message_fts MATCH ?
|
|
2274
|
+
AND f.namespace = ?
|
|
2275
|
+
${threadId === void 0 ? "" : includeUnthreaded ? "AND (m.thread_id = ? OR m.thread_id IS NULL)" : "AND m.thread_id = ?"}
|
|
2276
|
+
ORDER BY rank
|
|
2277
|
+
LIMIT ?
|
|
2278
|
+
`).all(...threadId === void 0 ? [match, key, boundedLimit] : [match, key, threadId, boundedLimit]);
|
|
2279
|
+
return rows.map(({ message_id }) => message_id);
|
|
2280
|
+
} catch {
|
|
2281
|
+
this.rawSearchFtsAvailable = false;
|
|
2282
|
+
return null;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
persistSnapshot(namespace, snapshot, expectedRevision, rawMessageIndexDelta) {
|
|
2231
2286
|
const current = this.database.prepare("SELECT revision FROM memory_spaces WHERE namespace = ?").get(namespace);
|
|
2232
2287
|
const actualRevision = current?.revision ?? null;
|
|
2233
2288
|
if ((actualRevision ?? 0) !== expectedRevision || actualRevision === null && expectedRevision !== 0) {
|
|
@@ -2346,6 +2401,14 @@ var SqliteStorage = class {
|
|
|
2346
2401
|
};
|
|
2347
2402
|
insertMessages(snapshot.openTail, null);
|
|
2348
2403
|
for (const block of snapshot.blocks) insertMessages(block.l5Raw, block.id);
|
|
2404
|
+
this.syncRawSearchIndex(namespace, rawMessageIndexDelta ?? {
|
|
2405
|
+
upsert: snapshot.blocks.flatMap(({ l5Raw }) => l5Raw),
|
|
2406
|
+
deleteIds: []
|
|
2407
|
+
});
|
|
2408
|
+
if (rawMessageIndexDelta) {
|
|
2409
|
+
const deleteMessage = this.database.prepare("DELETE FROM messages WHERE namespace = ? AND id = ?");
|
|
2410
|
+
for (const messageId of rawMessageIndexDelta.deleteIds) deleteMessage.run(namespace, messageId);
|
|
2411
|
+
}
|
|
2349
2412
|
const insertEvent = this.database.prepare(`
|
|
2350
2413
|
INSERT INTO events (
|
|
2351
2414
|
namespace, id, position, title, summary, narrative, tags_json, quotes_json, source_block_id,
|
|
@@ -2620,6 +2683,7 @@ var SqliteStorage = class {
|
|
|
2620
2683
|
this.immediateTransaction(() => {
|
|
2621
2684
|
this.database.exec(SCHEMA);
|
|
2622
2685
|
this.database.exec(THREAD_INDEXES);
|
|
2686
|
+
this.enableRawSearchFts();
|
|
2623
2687
|
this.database.exec(`PRAGMA user_version = ${STRATAGATE_STORAGE_SCHEMA_VERSION}`);
|
|
2624
2688
|
});
|
|
2625
2689
|
} else if (version >= 1 && version < STRATAGATE_STORAGE_SCHEMA_VERSION) {
|
|
@@ -2687,15 +2751,95 @@ var SqliteStorage = class {
|
|
|
2687
2751
|
this.database.exec("ALTER TABLE messages ADD COLUMN thread_id TEXT");
|
|
2688
2752
|
}
|
|
2689
2753
|
this.database.exec(THREAD_INDEXES);
|
|
2754
|
+
this.enableRawSearchFts();
|
|
2690
2755
|
this.database.prepare("UPDATE memory_spaces SET schema_version = ? WHERE schema_version < ?").run(STRATAGATE_STORAGE_SCHEMA_VERSION, STRATAGATE_STORAGE_SCHEMA_VERSION);
|
|
2691
2756
|
this.database.exec(`PRAGMA user_version = ${STRATAGATE_STORAGE_SCHEMA_VERSION}`);
|
|
2692
2757
|
});
|
|
2693
2758
|
} else if (version === STRATAGATE_STORAGE_SCHEMA_VERSION) {
|
|
2694
2759
|
this.database.exec(SCHEMA);
|
|
2695
2760
|
this.database.exec(THREAD_INDEXES);
|
|
2761
|
+
this.enableRawSearchFts();
|
|
2696
2762
|
}
|
|
2697
2763
|
this.assertSchemaVersion();
|
|
2698
2764
|
}
|
|
2765
|
+
enableRawSearchFts() {
|
|
2766
|
+
try {
|
|
2767
|
+
this.database.exec(RAW_MESSAGE_FTS_SCHEMA);
|
|
2768
|
+
this.rawSearchFtsAvailable = true;
|
|
2769
|
+
const namespaces = this.database.prepare("SELECT namespace FROM memory_spaces").all();
|
|
2770
|
+
for (const { namespace } of namespaces) {
|
|
2771
|
+
const state = this.database.prepare(
|
|
2772
|
+
"SELECT backfill_complete FROM raw_message_fts_state WHERE namespace = ?"
|
|
2773
|
+
).get(namespace);
|
|
2774
|
+
const messageCount = this.database.prepare(
|
|
2775
|
+
"SELECT COUNT(*) AS count FROM messages WHERE namespace = ? AND block_id IS NOT NULL"
|
|
2776
|
+
).get(namespace);
|
|
2777
|
+
const indexedCount = this.database.prepare(
|
|
2778
|
+
"SELECT COUNT(*) AS count FROM raw_message_fts_meta WHERE namespace = ?"
|
|
2779
|
+
).get(namespace);
|
|
2780
|
+
if (state?.backfill_complete === 1 && messageCount.count === indexedCount.count) continue;
|
|
2781
|
+
const messages = state?.backfill_complete === 1 ? this.database.prepare(`
|
|
2782
|
+
SELECT m.id, m.content
|
|
2783
|
+
FROM messages AS m
|
|
2784
|
+
LEFT JOIN raw_message_fts_meta AS i
|
|
2785
|
+
ON i.namespace = m.namespace AND i.message_id = m.id
|
|
2786
|
+
WHERE m.namespace = ? AND m.block_id IS NOT NULL AND i.message_id IS NULL
|
|
2787
|
+
`).all(namespace) : this.database.prepare(
|
|
2788
|
+
"SELECT id, content FROM messages WHERE namespace = ? AND block_id IS NOT NULL"
|
|
2789
|
+
).all(namespace);
|
|
2790
|
+
this.syncRawSearchIndex(namespace, { upsert: messages, deleteIds: [] });
|
|
2791
|
+
this.database.prepare(`
|
|
2792
|
+
INSERT INTO raw_message_fts_state (namespace, backfill_complete)
|
|
2793
|
+
VALUES (?, 1)
|
|
2794
|
+
ON CONFLICT (namespace) DO UPDATE SET backfill_complete = 1
|
|
2795
|
+
`).run(namespace);
|
|
2796
|
+
}
|
|
2797
|
+
} catch {
|
|
2798
|
+
this.rawSearchFtsAvailable = false;
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
syncRawSearchIndex(namespace, delta) {
|
|
2802
|
+
if (!this.rawSearchFtsAvailable) return;
|
|
2803
|
+
const findMeta = this.database.prepare(`
|
|
2804
|
+
SELECT message_id, tokens, fts_rowid
|
|
2805
|
+
FROM raw_message_fts_meta WHERE namespace = ? AND message_id = ?
|
|
2806
|
+
`);
|
|
2807
|
+
const deleteFts = this.database.prepare("DELETE FROM raw_message_fts WHERE rowid = ?");
|
|
2808
|
+
const deleteMeta = this.database.prepare("DELETE FROM raw_message_fts_meta WHERE namespace = ? AND message_id = ?");
|
|
2809
|
+
for (const messageId of delta.deleteIds) {
|
|
2810
|
+
const row = findMeta.get(namespace, messageId);
|
|
2811
|
+
if (!row) continue;
|
|
2812
|
+
deleteFts.run(row.fts_rowid);
|
|
2813
|
+
deleteMeta.run(namespace, messageId);
|
|
2814
|
+
}
|
|
2815
|
+
const insertFts = this.database.prepare(
|
|
2816
|
+
"INSERT INTO raw_message_fts (namespace, message_id, tokens) VALUES (?, ?, ?)"
|
|
2817
|
+
);
|
|
2818
|
+
const insertMeta = this.database.prepare(`
|
|
2819
|
+
INSERT INTO raw_message_fts_meta (namespace, message_id, tokens, fts_rowid)
|
|
2820
|
+
VALUES (?, ?, ?, ?)
|
|
2821
|
+
ON CONFLICT (namespace, message_id) DO UPDATE SET tokens = excluded.tokens, fts_rowid = excluded.fts_rowid
|
|
2822
|
+
`);
|
|
2823
|
+
for (const message of delta.upsert) {
|
|
2824
|
+
const messageId = message.id;
|
|
2825
|
+
const tokens = encodedRawSearchTokens(message.content);
|
|
2826
|
+
const previous = findMeta.get(namespace, messageId);
|
|
2827
|
+
if (previous?.tokens === tokens) continue;
|
|
2828
|
+
if (previous) deleteFts.run(previous.fts_rowid);
|
|
2829
|
+
if (!tokens) {
|
|
2830
|
+
if (previous) deleteMeta.run(namespace, messageId);
|
|
2831
|
+
continue;
|
|
2832
|
+
}
|
|
2833
|
+
insertFts.run(namespace, messageId, tokens);
|
|
2834
|
+
const row = this.database.prepare("SELECT last_insert_rowid() AS rowid").get();
|
|
2835
|
+
insertMeta.run(namespace, messageId, tokens, row.rowid);
|
|
2836
|
+
}
|
|
2837
|
+
this.database.prepare(`
|
|
2838
|
+
INSERT INTO raw_message_fts_state (namespace, backfill_complete)
|
|
2839
|
+
VALUES (?, 1)
|
|
2840
|
+
ON CONFLICT (namespace) DO UPDATE SET backfill_complete = 1
|
|
2841
|
+
`).run(namespace);
|
|
2842
|
+
}
|
|
2699
2843
|
assertSchemaVersion() {
|
|
2700
2844
|
const version = this.userVersion();
|
|
2701
2845
|
if (version !== STRATAGATE_STORAGE_SCHEMA_VERSION) {
|
|
@@ -2799,6 +2943,9 @@ var StrataGate = class _StrataGate {
|
|
|
2799
2943
|
successfulModelResponses = [];
|
|
2800
2944
|
ingestionReceipts = /* @__PURE__ */ new Map();
|
|
2801
2945
|
externalMemoryImportJobs = /* @__PURE__ */ new Map();
|
|
2946
|
+
rawMessageLookup = /* @__PURE__ */ new Map();
|
|
2947
|
+
pendingRawUpserts = /* @__PURE__ */ new Map();
|
|
2948
|
+
pendingRawDeletes = /* @__PURE__ */ new Set();
|
|
2802
2949
|
currentTurn = 0;
|
|
2803
2950
|
storage;
|
|
2804
2951
|
namespace;
|
|
@@ -3643,6 +3790,7 @@ var StrataGate = class _StrataGate {
|
|
|
3643
3790
|
if (receipt.eventIds.length === 0 && receipt.elementIds.length === 0) this.usageReceipts.delete(receiptId);
|
|
3644
3791
|
}
|
|
3645
3792
|
this.blocks.splice(sourceIndex, 1);
|
|
3793
|
+
this.markRawMessagesDeleted(sourceMessageIds);
|
|
3646
3794
|
return {
|
|
3647
3795
|
sourceBlockId: id,
|
|
3648
3796
|
removedEventIds: [...importedEventIds],
|
|
@@ -3894,24 +4042,40 @@ var StrataGate = class _StrataGate {
|
|
|
3894
4042
|
if (!element) throw new Error(`Unknown element: ${id}`);
|
|
3895
4043
|
return elementViewAt(element, at);
|
|
3896
4044
|
}
|
|
3897
|
-
searchRawMemory(query, limit = 6) {
|
|
4045
|
+
searchRawMemory(query, limit = 6, options = {}) {
|
|
3898
4046
|
const tokens = searchTokens(query);
|
|
3899
4047
|
if (tokens.length === 0) return [];
|
|
3900
|
-
const
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
}
|
|
4048
|
+
const boundedLimit = Math.max(1, Math.floor(limit));
|
|
4049
|
+
let candidateIds;
|
|
4050
|
+
try {
|
|
4051
|
+
candidateIds = this.storage?.searchRawMessageIds?.(
|
|
4052
|
+
this.namespace ?? "",
|
|
4053
|
+
tokens,
|
|
4054
|
+
Math.min(5e3, Math.max(100, boundedLimit * 20)),
|
|
4055
|
+
options.threadId,
|
|
4056
|
+
options.includeUnthreaded
|
|
4057
|
+
);
|
|
4058
|
+
} catch {
|
|
4059
|
+
candidateIds = null;
|
|
3913
4060
|
}
|
|
3914
|
-
|
|
4061
|
+
const candidates = candidateIds === null || candidateIds === void 0 ? this.blocks.flatMap((block) => block.l5Raw.map((message, index) => ({
|
|
4062
|
+
id: message.id,
|
|
4063
|
+
block,
|
|
4064
|
+
index,
|
|
4065
|
+
message
|
|
4066
|
+
}))).filter(({ message }) => options.threadId === void 0 || message.threadId === options.threadId || options.includeUnthreaded === true && message.threadId === void 0) : [...new Set(candidateIds)].flatMap((id) => {
|
|
4067
|
+
const item = this.rawMessageLookup.get(id);
|
|
4068
|
+
if (!item) return [];
|
|
4069
|
+
if (options.threadId !== void 0 && item.message.threadId !== options.threadId && !(options.includeUnthreaded === true && item.message.threadId === void 0)) return [];
|
|
4070
|
+
return [{ id, ...item }];
|
|
4071
|
+
});
|
|
4072
|
+
const ranked = bm25Rank(candidates, query, ({ message }) => searchTokens(message.content)).sort((left, right) => right.score - left.score || right.item.message.createdAt.localeCompare(left.item.message.createdAt) || right.item.block.sequence - left.item.block.sequence || right.item.index - left.item.index || left.item.id.localeCompare(right.item.id));
|
|
4073
|
+
return ranked.slice(0, boundedLimit).map(({ item }) => ({
|
|
4074
|
+
blockId: item.block.id,
|
|
4075
|
+
turnRange: [item.block.startTurn, item.block.endTurn],
|
|
4076
|
+
message: item.message,
|
|
4077
|
+
nearby: item.block.l5Raw.slice(Math.max(0, item.index - 1), item.index + 2)
|
|
4078
|
+
}));
|
|
3915
4079
|
}
|
|
3916
4080
|
/**
|
|
3917
4081
|
* Return decayed block views. Passing a threadId limits the result to that
|
|
@@ -4083,6 +4247,8 @@ var StrataGate = class _StrataGate {
|
|
|
4083
4247
|
lastLiftedBy: null
|
|
4084
4248
|
};
|
|
4085
4249
|
this.blocks.push(block);
|
|
4250
|
+
this.indexRawBlock(block);
|
|
4251
|
+
this.markRawMessagesForUpsert(block.l5Raw);
|
|
4086
4252
|
return block;
|
|
4087
4253
|
}
|
|
4088
4254
|
addEventInMemory(input) {
|
|
@@ -4247,6 +4413,28 @@ var StrataGate = class _StrataGate {
|
|
|
4247
4413
|
this.elementProjectionJobs.set(job.id, job);
|
|
4248
4414
|
return job;
|
|
4249
4415
|
}
|
|
4416
|
+
indexRawBlock(block) {
|
|
4417
|
+
for (const [index, message] of block.l5Raw.entries()) {
|
|
4418
|
+
this.rawMessageLookup.set(message.id, { block, index, message });
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
markRawMessagesForUpsert(messages) {
|
|
4422
|
+
for (const message of messages) {
|
|
4423
|
+
this.pendingRawDeletes.delete(message.id);
|
|
4424
|
+
this.pendingRawUpserts.set(message.id, structuredClone(message));
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
markRawMessagesDeleted(ids) {
|
|
4428
|
+
for (const id of ids) {
|
|
4429
|
+
this.pendingRawUpserts.delete(id);
|
|
4430
|
+
this.pendingRawDeletes.add(id);
|
|
4431
|
+
this.rawMessageLookup.delete(id);
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
rebuildRawMessageLookup() {
|
|
4435
|
+
this.rawMessageLookup.clear();
|
|
4436
|
+
for (const block of this.blocks) this.indexRawBlock(block);
|
|
4437
|
+
}
|
|
4250
4438
|
threadOpenTail(threadId) {
|
|
4251
4439
|
return this.openTail.filter((message) => message.threadId === threadId);
|
|
4252
4440
|
}
|
|
@@ -4325,6 +4513,8 @@ var StrataGate = class _StrataGate {
|
|
|
4325
4513
|
const remaining = this.openTail.filter((message) => !sealedIds.has(message.id));
|
|
4326
4514
|
this.openTail.splice(0, this.openTail.length, ...remaining);
|
|
4327
4515
|
this.blocks.push(block);
|
|
4516
|
+
this.indexRawBlock(block);
|
|
4517
|
+
this.markRawMessagesForUpsert(block.l5Raw);
|
|
4328
4518
|
const updatedAt = toUtc8Iso(this.now());
|
|
4329
4519
|
this.summaryJobs.set(block.id, {
|
|
4330
4520
|
blockId: block.id,
|
|
@@ -4558,6 +4748,8 @@ var StrataGate = class _StrataGate {
|
|
|
4558
4748
|
}
|
|
4559
4749
|
const before = this.exportSnapshot();
|
|
4560
4750
|
const beforeRevision = this.revision;
|
|
4751
|
+
const beforeRawUpserts = new Map(this.pendingRawUpserts);
|
|
4752
|
+
const beforeRawDeletes = new Set(this.pendingRawDeletes);
|
|
4561
4753
|
try {
|
|
4562
4754
|
const result = await mutation();
|
|
4563
4755
|
await this.persist();
|
|
@@ -4565,6 +4757,10 @@ var StrataGate = class _StrataGate {
|
|
|
4565
4757
|
} catch (error) {
|
|
4566
4758
|
this.restoreSnapshot(before);
|
|
4567
4759
|
this.revision = beforeRevision;
|
|
4760
|
+
this.pendingRawUpserts.clear();
|
|
4761
|
+
for (const [id, message] of beforeRawUpserts) this.pendingRawUpserts.set(id, message);
|
|
4762
|
+
this.pendingRawDeletes.clear();
|
|
4763
|
+
for (const id of beforeRawDeletes) this.pendingRawDeletes.add(id);
|
|
4568
4764
|
throw error;
|
|
4569
4765
|
} finally {
|
|
4570
4766
|
release();
|
|
@@ -4572,7 +4768,13 @@ var StrataGate = class _StrataGate {
|
|
|
4572
4768
|
}
|
|
4573
4769
|
async persist() {
|
|
4574
4770
|
if (!this.storage || !this.namespace) return;
|
|
4575
|
-
|
|
4771
|
+
const delta = {
|
|
4772
|
+
upsert: [...this.pendingRawUpserts.values()],
|
|
4773
|
+
deleteIds: [...this.pendingRawDeletes]
|
|
4774
|
+
};
|
|
4775
|
+
this.revision = await this.storage.save(this.namespace, this.exportSnapshot(), this.revision, delta);
|
|
4776
|
+
this.pendingRawUpserts.clear();
|
|
4777
|
+
this.pendingRawDeletes.clear();
|
|
4576
4778
|
}
|
|
4577
4779
|
restoreSnapshot(snapshot) {
|
|
4578
4780
|
const normalized = normalizeSnapshot(snapshot);
|
|
@@ -4584,6 +4786,9 @@ var StrataGate = class _StrataGate {
|
|
|
4584
4786
|
this.currentTurn = copy.currentTurn;
|
|
4585
4787
|
this.openTail.splice(0, this.openTail.length, ...copy.openTail);
|
|
4586
4788
|
this.blocks.splice(0, this.blocks.length, ...copy.blocks);
|
|
4789
|
+
this.rebuildRawMessageLookup();
|
|
4790
|
+
this.pendingRawUpserts.clear();
|
|
4791
|
+
this.pendingRawDeletes.clear();
|
|
4587
4792
|
this.summaryJobs.clear();
|
|
4588
4793
|
for (const job of copy.summaryJobs) this.summaryJobs.set(job.blockId, job);
|
|
4589
4794
|
this.events.splice(0, this.events.length, ...copy.events);
|
|
@@ -5667,6 +5872,20 @@ var SUPPORTED_RUNTIME_FAMILIES = [
|
|
|
5667
5872
|
"@deepseek-ai/dsh-tools": "0.1.5-rc.2",
|
|
5668
5873
|
"@deepseek-ai/schemastery": "3.18.2"
|
|
5669
5874
|
}
|
|
5875
|
+
},
|
|
5876
|
+
{
|
|
5877
|
+
cli: "0.1.6-alpha.1",
|
|
5878
|
+
versions: {
|
|
5879
|
+
"@deepseek-ai/cordis": "4.0.2",
|
|
5880
|
+
"@deepseek-ai/dsh-agent-default-model": "0.1.6-alpha.1",
|
|
5881
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.6-alpha.1",
|
|
5882
|
+
"@deepseek-ai/dsh-llm": "0.1.6-alpha.1",
|
|
5883
|
+
"@deepseek-ai/dsh-session": "0.1.6-alpha.1",
|
|
5884
|
+
"@deepseek-ai/dsh-settings": "0.1.6-alpha.1",
|
|
5885
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.6-alpha.1",
|
|
5886
|
+
"@deepseek-ai/dsh-tools": "0.1.6-alpha.1",
|
|
5887
|
+
"@deepseek-ai/schemastery": "3.18.2"
|
|
5888
|
+
}
|
|
5670
5889
|
}
|
|
5671
5890
|
];
|
|
5672
5891
|
function installedVersion(packageName) {
|
|
@@ -5689,7 +5908,7 @@ function classifyDshRuntime(packageVersions) {
|
|
|
5689
5908
|
if (family) return { cliVersion: family.cli, packageVersions };
|
|
5690
5909
|
const found = RUNTIME_PACKAGES.map((name2) => `${name2}@${packageVersions[name2]}`).join(", ");
|
|
5691
5910
|
throw new Error(
|
|
5692
|
-
`StrataGate cannot start because this DSH profile resolves an unsupported or mixed core runtime. Resolved: ${found}. Supported tested hosts are @deepseek-ai/dsh@0.1.2-rc.1 (internal DSH packages 0.1.2-rc.1) and @deepseek-ai/dsh@0.1.5-rc.1 (its real dependency tree uses internal DSH packages 0.1.5-rc.2). Reinstall or update stratagate-dsh through \`dsh plugin --profile <name> add <package>\` so the host supplies its peers.`
|
|
5911
|
+
`StrataGate cannot start because this DSH profile resolves an unsupported or mixed core runtime. Resolved: ${found}. Supported tested hosts are @deepseek-ai/dsh@0.1.2-rc.1 (internal DSH packages 0.1.2-rc.1) and @deepseek-ai/dsh@0.1.5-rc.1 (its real dependency tree uses internal DSH packages 0.1.5-rc.2), and @deepseek-ai/dsh@0.1.6-alpha.1 (internal DSH packages 0.1.6-alpha.1). Reinstall or update stratagate-dsh through \`dsh plugin --profile <name> add <package>\` so the host supplies its peers.`
|
|
5693
5912
|
);
|
|
5694
5913
|
}
|
|
5695
5914
|
function assertCompatibleDshRuntime() {
|
|
@@ -6104,7 +6323,7 @@ var StrataGateRuntime = class {
|
|
|
6104
6323
|
await this.flush();
|
|
6105
6324
|
const memory = await this.space(session);
|
|
6106
6325
|
const threadId = String(session.id);
|
|
6107
|
-
const results = memory.searchRawMemory(query, scope === "namespace" ?
|
|
6326
|
+
const results = memory.searchRawMemory(query, limit, scope === "namespace" ? {} : { threadId, includeUnthreaded: true }).slice(0, limit);
|
|
6108
6327
|
const blockTitles = new Map(memory.listBlocks().map((block) => [block.id, blockCitationTitle(block)]));
|
|
6109
6328
|
return this.batch(session, results.map((result, index) => ({
|
|
6110
6329
|
ref: `raw:${result.blockId}:${result.message.id}:${index}`,
|
|
@@ -8597,15 +8816,32 @@ async function memories(runtime, url) {
|
|
|
8597
8816
|
const offset = numeric(url.searchParams.get("offset"), 0, 0, Number.MAX_SAFE_INTEGER);
|
|
8598
8817
|
const limit = numeric(url.searchParams.get("limit"), 100, 1, 200);
|
|
8599
8818
|
let values;
|
|
8600
|
-
if (kind === "events")
|
|
8601
|
-
const
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8819
|
+
if (kind === "events") {
|
|
8820
|
+
const timeline = url.searchParams.get("timeline") === "true";
|
|
8821
|
+
const timeFilter = url.searchParams.get("time")?.trim() ?? "";
|
|
8822
|
+
const participant = url.searchParams.get("participant")?.trim() ?? "";
|
|
8823
|
+
const eventType = url.searchParams.get("eventType")?.trim() ?? "";
|
|
8824
|
+
const eventStatus = url.searchParams.get("eventStatus")?.trim() ?? "";
|
|
8825
|
+
const now = /* @__PURE__ */ new Date();
|
|
8826
|
+
const weekAgo = now.getTime() - 7 * 864e5;
|
|
8827
|
+
const occurrence = (event) => {
|
|
8828
|
+
const happened = event.temporal.happenedStart ?? event.temporal.happenedEnd;
|
|
8829
|
+
return { value: happened ?? event.temporal.mentionedAt ?? event.createdAt, known: Boolean(happened) };
|
|
8830
|
+
};
|
|
8831
|
+
values = [...snapshot.events].sort((left, right) => occurrence(right).value.localeCompare(occurrence(left).value)).filter((event) => !timeline || event.status !== "forgotten" && event.status !== "archived").filter((event) => !eventType || event.temporal.eventType === eventType).filter((event) => !eventStatus || event.temporal.status === eventStatus).filter((event) => !participant || (event.temporal.participantNodeIds ?? []).includes(participant)).filter((event) => {
|
|
8832
|
+
if (!timeFilter) return true;
|
|
8833
|
+
const info = occurrence(event);
|
|
8834
|
+
if (timeFilter === "unknown") return !info.known;
|
|
8835
|
+
const time = Date.parse(info.value);
|
|
8836
|
+
if (timeFilter === "today") return Number.isFinite(time) && new Date(time).toDateString() === now.toDateString();
|
|
8837
|
+
if (timeFilter === "week") return Number.isFinite(time) && time >= weekAgo;
|
|
8838
|
+
return true;
|
|
8839
|
+
}).map((event) => ({
|
|
8840
|
+
...eventSummary(event, snapshot),
|
|
8841
|
+
relatedNodes: snapshot.graphNodes.filter(({ id }) => (event.temporal.participantNodeIds ?? []).includes(id)).map(({ id, name: name2, type, aliases }) => ({ id, name: name2, type, aliases })),
|
|
8842
|
+
relatedElements: snapshot.elements.filter(({ sourceEventIds }) => sourceEventIds.includes(event.id)).map(({ id, name: name2 }) => ({ id, name: name2 }))
|
|
8843
|
+
}));
|
|
8844
|
+
} else if (kind === "graph") {
|
|
8609
8845
|
const eventMap = new Map(snapshot.events.map((event) => [event.id, event]));
|
|
8610
8846
|
return {
|
|
8611
8847
|
namespace,
|
|
@@ -9355,7 +9591,7 @@ async function apply(ctx, config) {
|
|
|
9355
9591
|
throw new Error(`StrataGate could not safely migrate legacy citation events: ${detail}`);
|
|
9356
9592
|
}
|
|
9357
9593
|
if (legacyMigration.migrated > 0) {
|
|
9358
|
-
ctx.logger.info(`stratagate-memory prepared ${legacyMigration.migrated} legacy Session generation(s) for DSH
|
|
9594
|
+
ctx.logger.info(`stratagate-memory prepared ${legacyMigration.migrated} legacy Session generation(s) for DSH ${compatibility.cliVersion}`);
|
|
9359
9595
|
}
|
|
9360
9596
|
await mkdir2(dirname3(resolved.database), { recursive: true });
|
|
9361
9597
|
const models = new DshModelBridge(ctx, resolved);
|