stratagate-dsh 0.2.35 → 0.2.37
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 +26 -16
- package/LICENSE +21 -21
- package/README.md +336 -133
- package/README.zh-CN.md +400 -0
- package/dist/client.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +583 -150
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +244 -0
- package/docs/DSH.md +191 -0
- package/docs/{README.zh-CN.md → DSH.zh-CN.md} +30 -27
- package/docs/EVALUATION.md +179 -0
- package/docs/EXTERNAL_MEMORY_IMPORT.zh-CN.md +54 -0
- package/docs/assets/stratagate-avatar.png +0 -0
- package/docs/assets/stratagate-how-it-works.en.png +0 -0
- package/docs/assets/stratagate-how-it-works.zh-CN.png +0 -0
- package/docs/assets/stratagate-knowledge-graph.png +0 -0
- package/docs/assets/stratagate-memory-structure.png +0 -0
- package/docs/assets/stratagate-short-term-memory.png +0 -0
- package/package.json +176 -153
- package/screenshots.json +4 -0
package/dist/index.js
CHANGED
|
@@ -15,7 +15,8 @@ var Config = z.object({
|
|
|
15
15
|
ingestSubagents: z.boolean().default(false),
|
|
16
16
|
provider: z.string(),
|
|
17
17
|
model: z.string(),
|
|
18
|
-
maxOutputTokens: z.natural().min(256).default(
|
|
18
|
+
maxOutputTokens: z.natural().min(256).default(2048),
|
|
19
|
+
structuredTaskTimeoutMs: z.natural().min(1e3).default(45e3)
|
|
19
20
|
});
|
|
20
21
|
function resolveConfig(config) {
|
|
21
22
|
const database = config.database?.trim() ?? "";
|
|
@@ -36,7 +37,8 @@ function resolveConfig(config) {
|
|
|
36
37
|
blockDecayLambda: Math.max(0, config.blockDecayLambda ?? 0.3),
|
|
37
38
|
ingestSubagents: config.ingestSubagents ?? false,
|
|
38
39
|
...provider && model ? { provider, model } : {},
|
|
39
|
-
maxOutputTokens: Math.max(256, Math.floor(config.maxOutputTokens ??
|
|
40
|
+
maxOutputTokens: Math.max(256, Math.floor(config.maxOutputTokens ?? 2048)),
|
|
41
|
+
structuredTaskTimeoutMs: Math.max(1e3, Math.floor(config.structuredTaskTimeoutMs ?? 45e3))
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
44
|
|
|
@@ -45,7 +47,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
45
47
|
import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
46
48
|
import { parameterSchemaSpecToJsonSchema, validateArgs } from "@deepseek-ai/dsh-tools";
|
|
47
49
|
|
|
48
|
-
//
|
|
50
|
+
// packages/core/src/blocks.ts
|
|
49
51
|
var DEFAULT_BLOCK_TURN_SIZE = 12;
|
|
50
52
|
var BLOCK_MAX_LEVEL = 5;
|
|
51
53
|
var BLOCK_DECAY_LAMBDA = 0.3;
|
|
@@ -252,7 +254,7 @@ function deterministicBlockLayers(messages) {
|
|
|
252
254
|
};
|
|
253
255
|
}
|
|
254
256
|
|
|
255
|
-
//
|
|
257
|
+
// packages/core/src/search.ts
|
|
256
258
|
var wordSegmenter = new Intl.Segmenter(void 0, { granularity: "word" });
|
|
257
259
|
function normalizeSearchText(value) {
|
|
258
260
|
return value.normalize("NFKC").toLocaleLowerCase().replace(/\s+/g, " ").trim();
|
|
@@ -329,7 +331,7 @@ function rrfRank(rankings) {
|
|
|
329
331
|
return [...fused.values()].sort((left, right) => right.score - left.score || left.bestRank - right.bestRank || left.item.id.localeCompare(right.item.id)).map(({ item, score }) => ({ item, score }));
|
|
330
332
|
}
|
|
331
333
|
|
|
332
|
-
//
|
|
334
|
+
// packages/core/src/graph.ts
|
|
333
335
|
var NODE_TYPES = /* @__PURE__ */ new Set(["person", "project", "organization", "tool", "place"]);
|
|
334
336
|
var STATUSES = /* @__PURE__ */ new Set(["active", "superseded", "disputed", "archived"]);
|
|
335
337
|
function text(value, limit = 240) {
|
|
@@ -467,7 +469,7 @@ function applyGraphProjection(options) {
|
|
|
467
469
|
return { nodeIds: [...touchedNodes], edgeIds: [...touchedEdges] };
|
|
468
470
|
}
|
|
469
471
|
|
|
470
|
-
//
|
|
472
|
+
// packages/core/src/events.ts
|
|
471
473
|
function normalizeStandardEventType(value) {
|
|
472
474
|
const normalized = normalizeSearchText(value ?? "").replace(/[\s_-]+/g, "");
|
|
473
475
|
const aliases = {
|
|
@@ -505,7 +507,7 @@ function normalizeStandardEventType(value) {
|
|
|
505
507
|
return aliases[normalized] ?? "other";
|
|
506
508
|
}
|
|
507
509
|
|
|
508
|
-
//
|
|
510
|
+
// packages/core/src/external-memory.ts
|
|
509
511
|
var EXTERNAL_MEMORY_EXPORT_SCHEMA = "stratagate.external-memory.v2";
|
|
510
512
|
var EXTERNAL_MEMORY_DECIDER_PROMPT_ZH_CN = `
|
|
511
513
|
\u4F60\u662F StrataGate \u7684\u5916\u90E8\u8BB0\u5FC6\u5408\u5E76\u88C1\u51B3\u5668\u3002\u8F93\u5165\u5305\u542B\u4E00\u4E2A\u5916\u90E8 candidate Event\uFF0C\u4EE5\u53CA\u672C\u5730\u68C0\u7D22\u5F97\u5230\u7684 Top-K existing Events\u3002\u53EA\u80FD\u4F9D\u636E candidate \u548C existing Events \u5224\u65AD\uFF0C\u4E0D\u5F97\u5F15\u5165\u5217\u8868\u4E4B\u5916\u7684\u672C\u5730\u4E8B\u4EF6\uFF0C\u4E5F\u4E0D\u5F97\u51ED\u5E38\u8BC6\u8865\u5168\u65F6\u95F4\u3002
|
|
@@ -1184,7 +1186,7 @@ function parseExternalMemoryExport(text3) {
|
|
|
1184
1186
|
}
|
|
1185
1187
|
var externalMemoryJsonExtractor = async ({ text: text3 }) => parseExternalMemoryExport(text3);
|
|
1186
1188
|
|
|
1187
|
-
//
|
|
1189
|
+
// packages/core/src/retrieval.ts
|
|
1188
1190
|
var RETRIEVAL_STRATEGIES = [
|
|
1189
1191
|
"answer",
|
|
1190
1192
|
"search_events",
|
|
@@ -1260,8 +1262,8 @@ function normalizeRetrievalAssessment(input, batchEvidenceRefs) {
|
|
|
1260
1262
|
};
|
|
1261
1263
|
}
|
|
1262
1264
|
|
|
1263
|
-
//
|
|
1264
|
-
var STRATAGATE_STORAGE_SCHEMA_VERSION =
|
|
1265
|
+
// packages/core/src/storage.ts
|
|
1266
|
+
var STRATAGATE_STORAGE_SCHEMA_VERSION = 9;
|
|
1265
1267
|
var KNOWLEDGE_GRAPH_PROJECTOR_VERSION = 1;
|
|
1266
1268
|
var StorageConflictError = class extends Error {
|
|
1267
1269
|
constructor(namespace, expectedRevision, actualRevision) {
|
|
@@ -1278,6 +1280,12 @@ var StorageConflictError = class extends Error {
|
|
|
1278
1280
|
function cloneSnapshot(snapshot) {
|
|
1279
1281
|
return structuredClone(snapshot);
|
|
1280
1282
|
}
|
|
1283
|
+
function readyLegacyBlocks(blocks) {
|
|
1284
|
+
return blocks.map((block) => ({ ...structuredClone(block), processingStatus: "ready" }));
|
|
1285
|
+
}
|
|
1286
|
+
function legacyExtractionJobs(jobs) {
|
|
1287
|
+
return jobs.map((job) => ({ ...structuredClone(job), nextRetryAt: null }));
|
|
1288
|
+
}
|
|
1281
1289
|
function emptyGraph() {
|
|
1282
1290
|
return { graphNodes: [], graphEdges: [], graphProjectionJobs: [] };
|
|
1283
1291
|
}
|
|
@@ -1285,7 +1293,7 @@ function migrateLegacyBlocks(blocks) {
|
|
|
1285
1293
|
return blocks.map((block) => {
|
|
1286
1294
|
const { pointerAnchorTurn, ...current } = block;
|
|
1287
1295
|
const position = blocks.filter((candidate) => candidate.threadId === block.threadId && candidate.endTurn <= pointerAnchorTurn).length;
|
|
1288
|
-
return { ...current, pointerAnchorBlockPosition: Math.max(1, position), lastLiftedBy: null };
|
|
1296
|
+
return { ...current, processingStatus: "ready", pointerAnchorBlockPosition: Math.max(1, position), lastLiftedBy: null };
|
|
1289
1297
|
});
|
|
1290
1298
|
}
|
|
1291
1299
|
function normalizeSnapshot(value) {
|
|
@@ -1299,6 +1307,8 @@ function normalizeSnapshot(value) {
|
|
|
1299
1307
|
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1300
1308
|
blockDecayLambda: BLOCK_DECAY_LAMBDA,
|
|
1301
1309
|
blocks: migrateLegacyBlocks(legacy.blocks),
|
|
1310
|
+
summaryJobs: [],
|
|
1311
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs),
|
|
1302
1312
|
elements: [],
|
|
1303
1313
|
elementProjectionJobs: [],
|
|
1304
1314
|
usageReceipts: Array.isArray(legacy.usageReceipts) ? legacy.usageReceipts.map((receipt) => ({ ...receipt, elementIds: [] })) : [],
|
|
@@ -1312,6 +1322,8 @@ function normalizeSnapshot(value) {
|
|
|
1312
1322
|
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1313
1323
|
blockDecayLambda: BLOCK_DECAY_LAMBDA,
|
|
1314
1324
|
blocks: migrateLegacyBlocks(legacy.blocks),
|
|
1325
|
+
summaryJobs: [],
|
|
1326
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs),
|
|
1315
1327
|
ingestionReceipts: [],
|
|
1316
1328
|
...emptyGraph()
|
|
1317
1329
|
};
|
|
@@ -1322,6 +1334,8 @@ function normalizeSnapshot(value) {
|
|
|
1322
1334
|
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1323
1335
|
blockDecayLambda: BLOCK_DECAY_LAMBDA,
|
|
1324
1336
|
blocks: migrateLegacyBlocks(legacy.blocks),
|
|
1337
|
+
summaryJobs: [],
|
|
1338
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs),
|
|
1325
1339
|
...emptyGraph()
|
|
1326
1340
|
};
|
|
1327
1341
|
} else if (schemaVersion === 4) {
|
|
@@ -1331,6 +1345,8 @@ function normalizeSnapshot(value) {
|
|
|
1331
1345
|
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1332
1346
|
blockDecayLambda: BLOCK_DECAY_LAMBDA,
|
|
1333
1347
|
blocks: migrateLegacyBlocks(legacy.blocks),
|
|
1348
|
+
summaryJobs: [],
|
|
1349
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs),
|
|
1334
1350
|
...emptyGraph()
|
|
1335
1351
|
};
|
|
1336
1352
|
} else if (schemaVersion === 5) {
|
|
@@ -1340,6 +1356,8 @@ function normalizeSnapshot(value) {
|
|
|
1340
1356
|
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1341
1357
|
blockDecayLambda: BLOCK_DECAY_LAMBDA,
|
|
1342
1358
|
blocks: migrateLegacyBlocks(legacy.blocks),
|
|
1359
|
+
summaryJobs: [],
|
|
1360
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs),
|
|
1343
1361
|
...emptyGraph()
|
|
1344
1362
|
};
|
|
1345
1363
|
} else if (schemaVersion === 6) {
|
|
@@ -1347,12 +1365,30 @@ function normalizeSnapshot(value) {
|
|
|
1347
1365
|
snapshot = {
|
|
1348
1366
|
...structuredClone(legacy),
|
|
1349
1367
|
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1350
|
-
blocks: legacy.blocks.map((block) => ({ ...structuredClone(block), lastLiftedBy: null })),
|
|
1368
|
+
blocks: readyLegacyBlocks(legacy.blocks.map((block) => ({ ...structuredClone(block), lastLiftedBy: null }))),
|
|
1369
|
+
summaryJobs: [],
|
|
1370
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs),
|
|
1351
1371
|
...emptyGraph()
|
|
1352
1372
|
};
|
|
1353
1373
|
} else if (schemaVersion === 7) {
|
|
1354
1374
|
const legacy = value;
|
|
1355
|
-
snapshot = {
|
|
1375
|
+
snapshot = {
|
|
1376
|
+
...structuredClone(legacy),
|
|
1377
|
+
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1378
|
+
blocks: readyLegacyBlocks(legacy.blocks),
|
|
1379
|
+
summaryJobs: [],
|
|
1380
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs),
|
|
1381
|
+
...emptyGraph()
|
|
1382
|
+
};
|
|
1383
|
+
} else if (schemaVersion === 8) {
|
|
1384
|
+
const legacy = value;
|
|
1385
|
+
snapshot = {
|
|
1386
|
+
...structuredClone(legacy),
|
|
1387
|
+
schemaVersion: STRATAGATE_STORAGE_SCHEMA_VERSION,
|
|
1388
|
+
blocks: readyLegacyBlocks(legacy.blocks),
|
|
1389
|
+
summaryJobs: [],
|
|
1390
|
+
extractionJobs: legacyExtractionJobs(legacy.extractionJobs)
|
|
1391
|
+
};
|
|
1356
1392
|
} else if (schemaVersion === STRATAGATE_STORAGE_SCHEMA_VERSION) {
|
|
1357
1393
|
snapshot = structuredClone(value);
|
|
1358
1394
|
} else {
|
|
@@ -1367,7 +1403,7 @@ function normalizeSnapshot(value) {
|
|
|
1367
1403
|
if (!Number.isFinite(snapshot.blockDecayLambda) || snapshot.blockDecayLambda < 0) {
|
|
1368
1404
|
throw new TypeError("Invalid StrataGate snapshot: blockDecayLambda must be a non-negative finite number");
|
|
1369
1405
|
}
|
|
1370
|
-
for (const key of ["openTail", "blocks", "events", "graphNodes", "graphEdges", "graphProjectionJobs", "elements", "extractionJobs", "elementProjectionJobs", "usageReceipts", "ingestionReceipts"]) {
|
|
1406
|
+
for (const key of ["openTail", "blocks", "summaryJobs", "events", "graphNodes", "graphEdges", "graphProjectionJobs", "elements", "extractionJobs", "elementProjectionJobs", "usageReceipts", "ingestionReceipts"]) {
|
|
1371
1407
|
if (!Array.isArray(snapshot[key])) throw new TypeError(`Invalid StrataGate snapshot: ${key} must be an array`);
|
|
1372
1408
|
}
|
|
1373
1409
|
if (!Array.isArray(snapshot.successfulModelResponses)) snapshot.successfulModelResponses = [];
|
|
@@ -1375,6 +1411,12 @@ function normalizeSnapshot(value) {
|
|
|
1375
1411
|
event.temporal = { ...event.temporal, eventType: normalizeStandardEventType(event.temporal.eventType) };
|
|
1376
1412
|
}
|
|
1377
1413
|
for (const block of snapshot.blocks) {
|
|
1414
|
+
if (block.processingStatus !== "pending" && block.processingStatus !== "ready") {
|
|
1415
|
+
throw new TypeError("Invalid StrataGate snapshot: Block processingStatus must be pending or ready");
|
|
1416
|
+
}
|
|
1417
|
+
if (block.processingStatus === "ready" && (!block.l0Title || !block.l1Summary || !Array.isArray(block.l0Tags) || !Array.isArray(block.l2Keypoints) || typeof block.shouldExtract !== "boolean")) {
|
|
1418
|
+
throw new TypeError("Invalid StrataGate snapshot: ready Block must contain validated L0-L2 layers");
|
|
1419
|
+
}
|
|
1378
1420
|
if (!Number.isSafeInteger(block.pointerAnchorBlockPosition) || block.pointerAnchorBlockPosition < 1) {
|
|
1379
1421
|
throw new TypeError("Invalid StrataGate snapshot: pointerAnchorBlockPosition must be a positive integer");
|
|
1380
1422
|
}
|
|
@@ -1391,7 +1433,7 @@ function assertValidSnapshot(value) {
|
|
|
1391
1433
|
normalizeSnapshot(value);
|
|
1392
1434
|
}
|
|
1393
1435
|
|
|
1394
|
-
//
|
|
1436
|
+
// packages/core/src/weights.ts
|
|
1395
1437
|
var BASE_DECAY = 0.15;
|
|
1396
1438
|
var REHEARSAL_FACTOR = 1.5;
|
|
1397
1439
|
function criticalityFloor(criticality) {
|
|
@@ -1410,7 +1452,7 @@ function memoryWeightAt(memory, currentTurn) {
|
|
|
1410
1452
|
return memory.weight.pinned ? 1 : capped;
|
|
1411
1453
|
}
|
|
1412
1454
|
|
|
1413
|
-
//
|
|
1455
|
+
// packages/core/src/elements.ts
|
|
1414
1456
|
var ELEMENT_TYPES = /* @__PURE__ */ new Set(["person", "project", "organization", "tool", "place"]);
|
|
1415
1457
|
var FACT_MODES = /* @__PURE__ */ new Set(["state", "set", "relation"]);
|
|
1416
1458
|
function compactText(value, limit) {
|
|
@@ -1533,10 +1575,10 @@ function elementViewAt(element, at) {
|
|
|
1533
1575
|
return view;
|
|
1534
1576
|
}
|
|
1535
1577
|
|
|
1536
|
-
//
|
|
1578
|
+
// packages/core/src/sqlite.ts
|
|
1537
1579
|
import { DatabaseSync } from "node:sqlite";
|
|
1538
1580
|
|
|
1539
|
-
//
|
|
1581
|
+
// packages/core/src/time.ts
|
|
1540
1582
|
var UTC8_OFFSET_MS = 8 * 60 * 60 * 1e3;
|
|
1541
1583
|
function toUtc8Iso(value = /* @__PURE__ */ new Date()) {
|
|
1542
1584
|
const date = value instanceof Date ? new Date(value.getTime()) : new Date(value);
|
|
@@ -1547,7 +1589,7 @@ function nowUtc8() {
|
|
|
1547
1589
|
return toUtc8Iso(/* @__PURE__ */ new Date());
|
|
1548
1590
|
}
|
|
1549
1591
|
|
|
1550
|
-
//
|
|
1592
|
+
// packages/core/src/sqlite.ts
|
|
1551
1593
|
var SCHEMA = `
|
|
1552
1594
|
CREATE TABLE IF NOT EXISTS memory_spaces (
|
|
1553
1595
|
namespace TEXT PRIMARY KEY,
|
|
@@ -1580,6 +1622,7 @@ CREATE TABLE IF NOT EXISTS blocks (
|
|
|
1580
1622
|
pointer_anchor_block_position INTEGER NOT NULL,
|
|
1581
1623
|
last_lifted_at TEXT,
|
|
1582
1624
|
last_lifted_by TEXT CHECK (last_lifted_by IS NULL OR last_lifted_by IN ('user', 'agent')),
|
|
1625
|
+
processing_status TEXT NOT NULL CHECK (processing_status IN ('pending', 'ready')),
|
|
1583
1626
|
PRIMARY KEY (namespace, id),
|
|
1584
1627
|
UNIQUE (namespace, sequence),
|
|
1585
1628
|
FOREIGN KEY (namespace) REFERENCES memory_spaces(namespace) ON DELETE CASCADE
|
|
@@ -1704,6 +1747,19 @@ CREATE TABLE IF NOT EXISTS extraction_jobs (
|
|
|
1704
1747
|
status TEXT NOT NULL,
|
|
1705
1748
|
attempts INTEGER NOT NULL,
|
|
1706
1749
|
last_error TEXT,
|
|
1750
|
+
next_retry_at TEXT,
|
|
1751
|
+
updated_at TEXT NOT NULL,
|
|
1752
|
+
PRIMARY KEY (namespace, block_id),
|
|
1753
|
+
FOREIGN KEY (namespace, block_id) REFERENCES blocks(namespace, id) ON DELETE CASCADE
|
|
1754
|
+
) STRICT;
|
|
1755
|
+
|
|
1756
|
+
CREATE TABLE IF NOT EXISTS block_summary_jobs (
|
|
1757
|
+
namespace TEXT NOT NULL,
|
|
1758
|
+
block_id TEXT NOT NULL,
|
|
1759
|
+
status TEXT NOT NULL,
|
|
1760
|
+
attempts INTEGER NOT NULL,
|
|
1761
|
+
last_error TEXT,
|
|
1762
|
+
next_retry_at TEXT,
|
|
1707
1763
|
updated_at TEXT NOT NULL,
|
|
1708
1764
|
PRIMARY KEY (namespace, block_id),
|
|
1709
1765
|
FOREIGN KEY (namespace, block_id) REFERENCES blocks(namespace, id) ON DELETE CASCADE
|
|
@@ -1844,11 +1900,14 @@ var SqliteStorage = class {
|
|
|
1844
1900
|
startTurn: row.start_turn,
|
|
1845
1901
|
endTurn: row.end_turn,
|
|
1846
1902
|
createdAt: row.created_at,
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1903
|
+
processingStatus: row.processing_status,
|
|
1904
|
+
...row.l0_title ? {
|
|
1905
|
+
shouldExtract: Boolean(row.should_extract),
|
|
1906
|
+
l0Title: row.l0_title,
|
|
1907
|
+
l0Tags: parseJson(row.l0_tags_json, "blocks.l0_tags_json"),
|
|
1908
|
+
l1Summary: row.l1_summary,
|
|
1909
|
+
l2Keypoints: parseJson(row.l2_keypoints_json, "blocks.l2_keypoints_json")
|
|
1910
|
+
} : {},
|
|
1852
1911
|
l3Condensed: row.l3_condensed,
|
|
1853
1912
|
l4Readable: row.l4_readable,
|
|
1854
1913
|
l5Raw: messagesByBlock.get(row.id) ?? [],
|
|
@@ -1858,6 +1917,17 @@ var SqliteStorage = class {
|
|
|
1858
1917
|
lastLiftedAt: row.last_lifted_at,
|
|
1859
1918
|
lastLiftedBy: row.last_lifted_by
|
|
1860
1919
|
}));
|
|
1920
|
+
const summaryJobs = this.database.prepare(`
|
|
1921
|
+
SELECT block_id, status, attempts, last_error, next_retry_at, updated_at
|
|
1922
|
+
FROM block_summary_jobs WHERE namespace = ? ORDER BY block_id
|
|
1923
|
+
`).all(key).map((row) => ({
|
|
1924
|
+
blockId: row.block_id,
|
|
1925
|
+
status: row.status,
|
|
1926
|
+
attempts: row.attempts,
|
|
1927
|
+
lastError: row.last_error,
|
|
1928
|
+
nextRetryAt: row.next_retry_at,
|
|
1929
|
+
updatedAt: row.updated_at
|
|
1930
|
+
}));
|
|
1861
1931
|
const sourceRows = this.database.prepare(`
|
|
1862
1932
|
SELECT event_id, message_id, position FROM event_sources
|
|
1863
1933
|
WHERE namespace = ? ORDER BY event_id, position
|
|
@@ -1969,13 +2039,14 @@ var SqliteStorage = class {
|
|
|
1969
2039
|
};
|
|
1970
2040
|
});
|
|
1971
2041
|
const extractionJobs = this.database.prepare(`
|
|
1972
|
-
SELECT block_id, status, attempts, last_error, updated_at
|
|
2042
|
+
SELECT block_id, status, attempts, last_error, next_retry_at, updated_at
|
|
1973
2043
|
FROM extraction_jobs WHERE namespace = ? ORDER BY block_id
|
|
1974
2044
|
`).all(key).map((row) => ({
|
|
1975
2045
|
blockId: row.block_id,
|
|
1976
2046
|
status: row.status,
|
|
1977
2047
|
attempts: row.attempts,
|
|
1978
2048
|
lastError: row.last_error,
|
|
2049
|
+
nextRetryAt: row.next_retry_at,
|
|
1979
2050
|
updatedAt: row.updated_at
|
|
1980
2051
|
}));
|
|
1981
2052
|
const elementProjectionJobs = this.database.prepare(`
|
|
@@ -2034,6 +2105,7 @@ var SqliteStorage = class {
|
|
|
2034
2105
|
blockDecayLambda: space.block_decay_lambda,
|
|
2035
2106
|
openTail,
|
|
2036
2107
|
blocks,
|
|
2108
|
+
summaryJobs,
|
|
2037
2109
|
events,
|
|
2038
2110
|
graphNodes,
|
|
2039
2111
|
graphEdges,
|
|
@@ -2104,8 +2176,9 @@ var SqliteStorage = class {
|
|
|
2104
2176
|
INSERT INTO blocks (
|
|
2105
2177
|
namespace, id, thread_id, sequence, start_turn, end_turn, created_at, should_extract,
|
|
2106
2178
|
l0_title, l0_tags_json, l1_summary, l2_keypoints_json, l3_condensed, l4_readable,
|
|
2107
|
-
pointer_current_level, pointer_anchor_level, pointer_anchor_block_position, last_lifted_at, last_lifted_by
|
|
2108
|
-
|
|
2179
|
+
pointer_current_level, pointer_anchor_level, pointer_anchor_block_position, last_lifted_at, last_lifted_by,
|
|
2180
|
+
processing_status
|
|
2181
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2109
2182
|
ON CONFLICT (namespace, id) DO UPDATE SET
|
|
2110
2183
|
thread_id = excluded.thread_id,
|
|
2111
2184
|
sequence = excluded.sequence,
|
|
@@ -2123,7 +2196,8 @@ var SqliteStorage = class {
|
|
|
2123
2196
|
pointer_anchor_level = excluded.pointer_anchor_level,
|
|
2124
2197
|
pointer_anchor_block_position = excluded.pointer_anchor_block_position,
|
|
2125
2198
|
last_lifted_at = excluded.last_lifted_at,
|
|
2126
|
-
last_lifted_by = excluded.last_lifted_by
|
|
2199
|
+
last_lifted_by = excluded.last_lifted_by,
|
|
2200
|
+
processing_status = excluded.processing_status
|
|
2127
2201
|
`);
|
|
2128
2202
|
for (const block of snapshot.blocks) {
|
|
2129
2203
|
insertBlock.run(
|
|
@@ -2134,18 +2208,19 @@ var SqliteStorage = class {
|
|
|
2134
2208
|
block.startTurn,
|
|
2135
2209
|
block.endTurn,
|
|
2136
2210
|
block.createdAt,
|
|
2137
|
-
Number(block.shouldExtract),
|
|
2138
|
-
block.l0Title,
|
|
2139
|
-
JSON.stringify(block.l0Tags),
|
|
2140
|
-
block.l1Summary,
|
|
2141
|
-
JSON.stringify(block.l2Keypoints),
|
|
2211
|
+
Number(block.shouldExtract ?? false),
|
|
2212
|
+
block.l0Title ?? "",
|
|
2213
|
+
JSON.stringify(block.l0Tags ?? []),
|
|
2214
|
+
block.l1Summary ?? "",
|
|
2215
|
+
JSON.stringify(block.l2Keypoints ?? []),
|
|
2142
2216
|
block.l3Condensed,
|
|
2143
2217
|
block.l4Readable,
|
|
2144
2218
|
block.pointerCurrentLevel,
|
|
2145
2219
|
block.pointerAnchorLevel,
|
|
2146
2220
|
block.pointerAnchorBlockPosition,
|
|
2147
2221
|
block.lastLiftedAt,
|
|
2148
|
-
block.lastLiftedBy
|
|
2222
|
+
block.lastLiftedBy,
|
|
2223
|
+
block.processingStatus
|
|
2149
2224
|
);
|
|
2150
2225
|
}
|
|
2151
2226
|
const insertMessage = this.database.prepare(`
|
|
@@ -2331,16 +2406,31 @@ var SqliteStorage = class {
|
|
|
2331
2406
|
}
|
|
2332
2407
|
const insertJob = this.database.prepare(`
|
|
2333
2408
|
INSERT INTO extraction_jobs (
|
|
2334
|
-
namespace, block_id, status, attempts, last_error, updated_at
|
|
2335
|
-
) VALUES (?, ?, ?, ?, ?, ?)
|
|
2409
|
+
namespace, block_id, status, attempts, last_error, next_retry_at, updated_at
|
|
2410
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
2336
2411
|
ON CONFLICT (namespace, block_id) DO UPDATE SET
|
|
2337
2412
|
status = excluded.status,
|
|
2338
2413
|
attempts = excluded.attempts,
|
|
2339
2414
|
last_error = excluded.last_error,
|
|
2415
|
+
next_retry_at = excluded.next_retry_at,
|
|
2340
2416
|
updated_at = excluded.updated_at
|
|
2341
2417
|
`);
|
|
2342
2418
|
for (const job of snapshot.extractionJobs) {
|
|
2343
|
-
insertJob.run(namespace, job.blockId, job.status, job.attempts, job.lastError, job.updatedAt);
|
|
2419
|
+
insertJob.run(namespace, job.blockId, job.status, job.attempts, job.lastError, job.nextRetryAt, job.updatedAt);
|
|
2420
|
+
}
|
|
2421
|
+
const insertSummaryJob = this.database.prepare(`
|
|
2422
|
+
INSERT INTO block_summary_jobs (
|
|
2423
|
+
namespace, block_id, status, attempts, last_error, next_retry_at, updated_at
|
|
2424
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
2425
|
+
ON CONFLICT (namespace, block_id) DO UPDATE SET
|
|
2426
|
+
status = excluded.status,
|
|
2427
|
+
attempts = excluded.attempts,
|
|
2428
|
+
last_error = excluded.last_error,
|
|
2429
|
+
next_retry_at = excluded.next_retry_at,
|
|
2430
|
+
updated_at = excluded.updated_at
|
|
2431
|
+
`);
|
|
2432
|
+
for (const job of snapshot.summaryJobs) {
|
|
2433
|
+
insertSummaryJob.run(namespace, job.blockId, job.status, job.attempts, job.lastError, job.nextRetryAt, job.updatedAt);
|
|
2344
2434
|
}
|
|
2345
2435
|
const insertElementProjectionJob = this.database.prepare(`
|
|
2346
2436
|
INSERT INTO element_projection_jobs (
|
|
@@ -2429,7 +2519,7 @@ var SqliteStorage = class {
|
|
|
2429
2519
|
this.database.exec(THREAD_INDEXES);
|
|
2430
2520
|
this.database.exec(`PRAGMA user_version = ${STRATAGATE_STORAGE_SCHEMA_VERSION}`);
|
|
2431
2521
|
});
|
|
2432
|
-
} else if (version
|
|
2522
|
+
} else if (version >= 1 && version < STRATAGATE_STORAGE_SCHEMA_VERSION) {
|
|
2433
2523
|
this.immediateTransaction(() => {
|
|
2434
2524
|
this.database.exec(SCHEMA);
|
|
2435
2525
|
if (version === 1) {
|
|
@@ -2465,6 +2555,13 @@ var SqliteStorage = class {
|
|
|
2465
2555
|
if (!blockColumns.some(({ name: name2 }) => name2 === "last_lifted_by")) {
|
|
2466
2556
|
this.database.exec("ALTER TABLE blocks ADD COLUMN last_lifted_by TEXT CHECK (last_lifted_by IS NULL OR last_lifted_by IN ('user', 'agent'))");
|
|
2467
2557
|
}
|
|
2558
|
+
if (!blockColumns.some(({ name: name2 }) => name2 === "processing_status")) {
|
|
2559
|
+
this.database.exec("ALTER TABLE blocks ADD COLUMN processing_status TEXT NOT NULL DEFAULT 'ready' CHECK (processing_status IN ('pending', 'ready'))");
|
|
2560
|
+
}
|
|
2561
|
+
const extractionColumns = this.database.prepare("PRAGMA table_info('extraction_jobs')").all();
|
|
2562
|
+
if (!extractionColumns.some(({ name: name2 }) => name2 === "next_retry_at")) {
|
|
2563
|
+
this.database.exec("ALTER TABLE extraction_jobs ADD COLUMN next_retry_at TEXT");
|
|
2564
|
+
}
|
|
2468
2565
|
const messageColumns = this.database.prepare("PRAGMA table_info('messages')").all();
|
|
2469
2566
|
if (!messageColumns.some(({ name: name2 }) => name2 === "thread_id")) {
|
|
2470
2567
|
this.database.exec("ALTER TABLE messages ADD COLUMN thread_id TEXT");
|
|
@@ -2512,7 +2609,7 @@ var SqliteStorage = class {
|
|
|
2512
2609
|
}
|
|
2513
2610
|
};
|
|
2514
2611
|
|
|
2515
|
-
//
|
|
2612
|
+
// packages/core/src/store.ts
|
|
2516
2613
|
function defaultIdFactory(prefix) {
|
|
2517
2614
|
return `${prefix}_${crypto.randomUUID()}`;
|
|
2518
2615
|
}
|
|
@@ -2522,21 +2619,13 @@ function defaultElementIdFactory(prefix) {
|
|
|
2522
2619
|
function defaultGraphIdFactory(prefix) {
|
|
2523
2620
|
return `${prefix}_${crypto.randomUUID()}`;
|
|
2524
2621
|
}
|
|
2525
|
-
function defaultSummary(messages) {
|
|
2526
|
-
const natural = messages.filter((message) => message.role === "user" || message.role === "assistant");
|
|
2527
|
-
const firstUser = natural.find((message) => message.role === "user");
|
|
2528
|
-
return {
|
|
2529
|
-
l0Title: (firstUser?.content ?? "Conversation block").replace(/\s+/g, " ").trim().slice(0, 80),
|
|
2530
|
-
l0Tags: [],
|
|
2531
|
-
l1Summary: natural.slice(0, 4).map((message) => message.content.replace(/\s+/g, " ").trim()).join(" ").slice(0, 500),
|
|
2532
|
-
l2Keypoints: natural.slice(0, 8).map((message) => message.content.replace(/\s+/g, " ").trim().slice(0, 160)),
|
|
2533
|
-
shouldExtract: false
|
|
2534
|
-
};
|
|
2535
|
-
}
|
|
2536
2622
|
function renderBlock(block, level) {
|
|
2623
|
+
if (block.processingStatus !== "ready" || !block.l0Title || !block.l0Tags || !block.l1Summary || !block.l2Keypoints) {
|
|
2624
|
+
throw new Error(`Block ${block.id} is not ready for rendering`);
|
|
2625
|
+
}
|
|
2537
2626
|
if (level === 0) return `${block.l0Title}
|
|
2538
2627
|
Tags: ${block.l0Tags.join(", ") || "none"}`;
|
|
2539
|
-
if (level === 1) return block.l1Summary
|
|
2628
|
+
if (level === 1) return block.l1Summary;
|
|
2540
2629
|
if (level === 2) return block.l2Keypoints.map((point) => `- ${point}`).join("\n") || block.l1Summary;
|
|
2541
2630
|
if (level === 3) return block.l3Condensed;
|
|
2542
2631
|
if (level === 4) return block.l4Readable;
|
|
@@ -2553,8 +2642,10 @@ function errorMessage(error) {
|
|
|
2553
2642
|
return error instanceof Error ? error.message : String(error);
|
|
2554
2643
|
}
|
|
2555
2644
|
var STRATAGATE_CONSTRUCTOR_TOKEN = /* @__PURE__ */ Symbol("StrataGate constructor");
|
|
2645
|
+
var DERIVATION_MAX_ATTEMPTS = 3;
|
|
2646
|
+
var DERIVATION_BACKOFF_MS = 1e3;
|
|
2556
2647
|
var StrataGate = class _StrataGate {
|
|
2557
|
-
|
|
2648
|
+
blockTurnSizeValue;
|
|
2558
2649
|
blockDecayLambdaValue;
|
|
2559
2650
|
summarizer;
|
|
2560
2651
|
extractor;
|
|
@@ -2572,6 +2663,7 @@ var StrataGate = class _StrataGate {
|
|
|
2572
2663
|
graphNodes = [];
|
|
2573
2664
|
graphEdges = [];
|
|
2574
2665
|
extractionJobs = /* @__PURE__ */ new Map();
|
|
2666
|
+
summaryJobs = /* @__PURE__ */ new Map();
|
|
2575
2667
|
elementProjectionJobs = /* @__PURE__ */ new Map();
|
|
2576
2668
|
graphProjectionJobs = /* @__PURE__ */ new Map();
|
|
2577
2669
|
usageReceipts = /* @__PURE__ */ new Map();
|
|
@@ -2586,7 +2678,7 @@ var StrataGate = class _StrataGate {
|
|
|
2586
2678
|
if (token !== STRATAGATE_CONSTRUCTOR_TOKEN) {
|
|
2587
2679
|
throw new TypeError("Use StrataGate.open() for SQLite or StrataGate.inMemory() for explicit ephemeral storage");
|
|
2588
2680
|
}
|
|
2589
|
-
this.
|
|
2681
|
+
this.blockTurnSizeValue = Math.max(1, Math.floor(options.blockTurnSize ?? DEFAULT_BLOCK_TURN_SIZE));
|
|
2590
2682
|
const blockDecayLambda = options.blockDecayLambda ?? BLOCK_DECAY_LAMBDA;
|
|
2591
2683
|
if (!Number.isFinite(blockDecayLambda) || blockDecayLambda < 0) {
|
|
2592
2684
|
throw new TypeError("blockDecayLambda must be a non-negative finite number");
|
|
@@ -2680,6 +2772,21 @@ var StrataGate = class _StrataGate {
|
|
|
2680
2772
|
if (loaded && loadedSnapshot) {
|
|
2681
2773
|
memory.restoreSnapshot(loadedSnapshot);
|
|
2682
2774
|
memory.revision = loadedRevision;
|
|
2775
|
+
const interruptedSummaries = [...memory.summaryJobs.values()].filter((job) => job.status === "running");
|
|
2776
|
+
if (interruptedSummaries.length > 0) {
|
|
2777
|
+
await memory.commitMutation(() => {
|
|
2778
|
+
const now = toUtc8Iso(memory.now());
|
|
2779
|
+
for (const job of interruptedSummaries) {
|
|
2780
|
+
memory.summaryJobs.set(job.blockId, {
|
|
2781
|
+
...job,
|
|
2782
|
+
status: "failed",
|
|
2783
|
+
lastError: "Block summarization was interrupted before completion.",
|
|
2784
|
+
nextRetryAt: now,
|
|
2785
|
+
updatedAt: now
|
|
2786
|
+
});
|
|
2787
|
+
}
|
|
2788
|
+
});
|
|
2789
|
+
}
|
|
2683
2790
|
const interrupted = [...memory.extractionJobs.values()].filter((job) => job.status === "running");
|
|
2684
2791
|
if (interrupted.length > 0) {
|
|
2685
2792
|
await memory.commitMutation(() => {
|
|
@@ -2689,6 +2796,7 @@ var StrataGate = class _StrataGate {
|
|
|
2689
2796
|
...job,
|
|
2690
2797
|
status: "failed",
|
|
2691
2798
|
lastError: "Extraction was interrupted before completion.",
|
|
2799
|
+
nextRetryAt: now,
|
|
2692
2800
|
updatedAt: now
|
|
2693
2801
|
});
|
|
2694
2802
|
}
|
|
@@ -2734,6 +2842,18 @@ var StrataGate = class _StrataGate {
|
|
|
2734
2842
|
get storageRevision() {
|
|
2735
2843
|
return this.revision;
|
|
2736
2844
|
}
|
|
2845
|
+
get blockTurnSize() {
|
|
2846
|
+
return this.blockTurnSizeValue;
|
|
2847
|
+
}
|
|
2848
|
+
async setBlockTurnSize(value) {
|
|
2849
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
2850
|
+
throw new TypeError("blockTurnSize must be a positive integer");
|
|
2851
|
+
}
|
|
2852
|
+
if (value === this.blockTurnSizeValue) return;
|
|
2853
|
+
await this.commitMutation(() => {
|
|
2854
|
+
this.blockTurnSizeValue = value;
|
|
2855
|
+
});
|
|
2856
|
+
}
|
|
2737
2857
|
get blockDecayLambda() {
|
|
2738
2858
|
return this.blockDecayLambdaValue;
|
|
2739
2859
|
}
|
|
@@ -2768,6 +2888,9 @@ var StrataGate = class _StrataGate {
|
|
|
2768
2888
|
listExtractionJobs() {
|
|
2769
2889
|
return [...this.extractionJobs.values()];
|
|
2770
2890
|
}
|
|
2891
|
+
listSummaryJobs() {
|
|
2892
|
+
return [...this.summaryJobs.values()];
|
|
2893
|
+
}
|
|
2771
2894
|
listElementProjectionJobs() {
|
|
2772
2895
|
return [...this.elementProjectionJobs.values()];
|
|
2773
2896
|
}
|
|
@@ -2800,6 +2923,7 @@ var StrataGate = class _StrataGate {
|
|
|
2800
2923
|
blockDecayLambda: this.blockDecayLambda,
|
|
2801
2924
|
openTail: this.openTail,
|
|
2802
2925
|
blocks: this.blocks,
|
|
2926
|
+
summaryJobs: [...this.summaryJobs.values()],
|
|
2803
2927
|
events: this.events,
|
|
2804
2928
|
graphNodes: this.graphNodes,
|
|
2805
2929
|
graphEdges: this.graphEdges,
|
|
@@ -2848,57 +2972,55 @@ var StrataGate = class _StrataGate {
|
|
|
2848
2972
|
if (receiptId) this.ingestionReceipts.set(receiptId, { id: receiptId, createdAt });
|
|
2849
2973
|
return true;
|
|
2850
2974
|
});
|
|
2851
|
-
if (!appended) return { sealedBlock: null, extractedEvents: [], projectedElements: [] };
|
|
2975
|
+
if (!appended) return { sealedBlock: null, readyBlocks: [], extractedEvents: [], projectedElements: [] };
|
|
2852
2976
|
if (options.deferProcessing === true) {
|
|
2853
|
-
return { sealedBlock: null, extractedEvents: [], projectedElements: [] };
|
|
2977
|
+
return { sealedBlock: null, readyBlocks: [], extractedEvents: [], projectedElements: [] };
|
|
2854
2978
|
}
|
|
2855
2979
|
if (this.threadOpenTail(threadId).filter((message) => message.role === "user").length < this.blockTurnSize) {
|
|
2856
2980
|
const projectedElements2 = await this.projectEligibleElements() ?? [];
|
|
2857
2981
|
await this.projectEligibleGraph();
|
|
2858
|
-
return { sealedBlock: null, extractedEvents: [], projectedElements: projectedElements2 };
|
|
2982
|
+
return { sealedBlock: null, readyBlocks: [], extractedEvents: [], projectedElements: projectedElements2 };
|
|
2859
2983
|
}
|
|
2860
2984
|
const sealedBlock = await this.sealOpenTail(threadId);
|
|
2861
|
-
|
|
2985
|
+
if (options.deferDerivation === true) {
|
|
2986
|
+
return { sealedBlock, readyBlocks: [], extractedEvents: [], projectedElements: [] };
|
|
2987
|
+
}
|
|
2988
|
+
const beforeReady = sealedBlock.processingStatus === "ready";
|
|
2989
|
+
const extractedEvents = await this.processBlock(sealedBlock, { retryFailed: false });
|
|
2990
|
+
const readyBlocks = !beforeReady && sealedBlock.processingStatus === "ready" ? [sealedBlock] : [];
|
|
2862
2991
|
const projectedElements = await this.projectEligibleElements() ?? [];
|
|
2863
2992
|
await this.projectEligibleGraph();
|
|
2864
|
-
return { sealedBlock, extractedEvents, projectedElements };
|
|
2993
|
+
return { sealedBlock, readyBlocks, extractedEvents, projectedElements };
|
|
2865
2994
|
}
|
|
2866
2995
|
async resumePendingWork(options = {}) {
|
|
2867
2996
|
const sealedBlocks = [];
|
|
2997
|
+
const readyBlocks = [];
|
|
2868
2998
|
const extractedEvents = [];
|
|
2869
2999
|
const projectedElements = [];
|
|
2870
3000
|
while (true) {
|
|
2871
3001
|
const sealable = this.nextSealableThread();
|
|
2872
3002
|
if (sealable === null) break;
|
|
2873
3003
|
sealedBlocks.push(await this.sealOpenTail(sealable.threadId));
|
|
2874
|
-
extractedEvents.push(...await this.extractEligibleBlock() ?? []);
|
|
2875
|
-
projectedElements.push(...await this.projectEligibleElements() ?? []);
|
|
2876
|
-
await this.projectEligibleGraph();
|
|
2877
3004
|
}
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
3005
|
+
if (options.deferDerivation === true) {
|
|
3006
|
+
return { sealedBlocks, readyBlocks, extractedEvents, projectedElements };
|
|
3007
|
+
}
|
|
3008
|
+
for (const block of this.blocks) {
|
|
3009
|
+
if (options.threadId !== void 0 && block.threadId !== options.threadId) continue;
|
|
3010
|
+
if (block.processingStatus === "ready") continue;
|
|
3011
|
+
const extracted = await this.processBlock(block, { retryFailed: options.retryFailed === true });
|
|
2881
3012
|
extractedEvents.push(...extracted);
|
|
3013
|
+
if (this.blocks.find((candidate) => candidate.id === block.id)?.processingStatus === "ready") readyBlocks.push(block);
|
|
2882
3014
|
projectedElements.push(...await this.projectEligibleElements() ?? []);
|
|
2883
3015
|
await this.projectEligibleGraph();
|
|
2884
3016
|
}
|
|
2885
|
-
if (options.retrySkipped === true) {
|
|
2886
|
-
const skippedBlockIds = this.blocks.filter((block) => this.nextBlockInThread(block) !== null && block.shouldExtract && this.extractionJobs.get(block.id)?.status === "skipped").map((block) => block.id);
|
|
2887
|
-
for (const blockId of skippedBlockIds) {
|
|
2888
|
-
const extracted = await this.extractEligibleBlock({ blockId, includeSkipped: true });
|
|
2889
|
-
if (extracted === null) continue;
|
|
2890
|
-
extractedEvents.push(...extracted);
|
|
2891
|
-
projectedElements.push(...await this.projectEligibleElements() ?? []);
|
|
2892
|
-
await this.projectEligibleGraph();
|
|
2893
|
-
}
|
|
2894
|
-
}
|
|
2895
3017
|
while (true) {
|
|
2896
3018
|
const projected = await this.projectEligibleElements();
|
|
2897
3019
|
if (projected === null) break;
|
|
2898
3020
|
projectedElements.push(...projected);
|
|
2899
3021
|
}
|
|
2900
3022
|
await this.projectEligibleGraph();
|
|
2901
|
-
return { sealedBlocks, extractedEvents, projectedElements };
|
|
3023
|
+
return { sealedBlocks, readyBlocks, extractedEvents, projectedElements };
|
|
2902
3024
|
}
|
|
2903
3025
|
async addEvent(input) {
|
|
2904
3026
|
return this.commitMutation(() => {
|
|
@@ -3260,9 +3382,9 @@ var StrataGate = class _StrataGate {
|
|
|
3260
3382
|
* StrataGate namespace (never another namespace).
|
|
3261
3383
|
*/
|
|
3262
3384
|
getBlockContext(threadId) {
|
|
3263
|
-
const blocks = threadId === void 0 ? this.blocks : this.blocks.filter((block) => block.threadId === threadId);
|
|
3385
|
+
const blocks = threadId === void 0 ? this.blocks.filter((block) => block.processingStatus === "ready") : this.blocks.filter((block) => block.threadId === threadId && block.processingStatus === "ready");
|
|
3264
3386
|
return blocks.map((block) => {
|
|
3265
|
-
const threadBlocks = this.threadBlocks(block.threadId);
|
|
3387
|
+
const threadBlocks = this.threadBlocks(block.threadId).filter((candidate) => candidate.processingStatus === "ready");
|
|
3266
3388
|
const latestBlockPosition = threadBlocks.length;
|
|
3267
3389
|
const blockPosition = threadBlocks.indexOf(block) + 1;
|
|
3268
3390
|
const age = Math.max(0, latestBlockPosition - blockPosition);
|
|
@@ -3288,8 +3410,10 @@ var StrataGate = class _StrataGate {
|
|
|
3288
3410
|
return this.commitMutation(() => {
|
|
3289
3411
|
const block = this.blocks.find((candidate) => candidate.id === id);
|
|
3290
3412
|
if (!block) throw new Error(`Unknown block: ${id}`);
|
|
3291
|
-
|
|
3292
|
-
const
|
|
3413
|
+
if (block.processingStatus !== "ready") throw new Error(`Block ${id} is not ready for decay or expansion`);
|
|
3414
|
+
const readyBlocks = this.threadBlocks(block.threadId).filter((candidate) => candidate.processingStatus === "ready");
|
|
3415
|
+
const latestBlockPosition = readyBlocks.length;
|
|
3416
|
+
const blockPosition = readyBlocks.indexOf(block) + 1;
|
|
3293
3417
|
const current = getDecayedBlockLevel(
|
|
3294
3418
|
block.pointerAnchorLevel,
|
|
3295
3419
|
block.pointerAnchorBlockPosition,
|
|
@@ -3408,6 +3532,7 @@ var StrataGate = class _StrataGate {
|
|
|
3408
3532
|
l1Summary: text3.replace(/\s+/gu, " ").trim().slice(0, 500),
|
|
3409
3533
|
l2Keypoints: text3.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean).slice(0, 8),
|
|
3410
3534
|
shouldExtract: false,
|
|
3535
|
+
processingStatus: "ready",
|
|
3411
3536
|
...deterministicBlockLayers([message]),
|
|
3412
3537
|
pointerCurrentLevel: 5,
|
|
3413
3538
|
pointerAnchorLevel: 5,
|
|
@@ -3624,7 +3749,6 @@ var StrataGate = class _StrataGate {
|
|
|
3624
3749
|
if (raw.filter((message) => message.role === "user").length < this.blockTurnSize) {
|
|
3625
3750
|
throw new Error("Open tail does not contain enough turns to seal a block");
|
|
3626
3751
|
}
|
|
3627
|
-
const generated = this.summarizer ? await this.summarizer(raw) : defaultSummary(raw);
|
|
3628
3752
|
const deterministic = deterministicBlockLayers(raw);
|
|
3629
3753
|
const sequence = this.blocks.length + 1;
|
|
3630
3754
|
const threadBlocks = this.threadBlocks(threadId);
|
|
@@ -3644,11 +3768,7 @@ var StrataGate = class _StrataGate {
|
|
|
3644
3768
|
startTurn,
|
|
3645
3769
|
endTurn,
|
|
3646
3770
|
createdAt: raw.at(-1)?.createdAt ?? toUtc8Iso(this.now()),
|
|
3647
|
-
|
|
3648
|
-
l0Tags: generated.l0Tags,
|
|
3649
|
-
l1Summary: generated.l1Summary,
|
|
3650
|
-
l2Keypoints: generated.l2Keypoints,
|
|
3651
|
-
shouldExtract: generated.shouldExtract,
|
|
3771
|
+
processingStatus: "pending",
|
|
3652
3772
|
...deterministic,
|
|
3653
3773
|
pointerCurrentLevel: 5,
|
|
3654
3774
|
pointerAnchorLevel: 5,
|
|
@@ -3660,27 +3780,132 @@ var StrataGate = class _StrataGate {
|
|
|
3660
3780
|
const remaining = this.openTail.filter((message) => !sealedIds.has(message.id));
|
|
3661
3781
|
this.openTail.splice(0, this.openTail.length, ...remaining);
|
|
3662
3782
|
this.blocks.push(block);
|
|
3783
|
+
const updatedAt = toUtc8Iso(this.now());
|
|
3784
|
+
this.summaryJobs.set(block.id, {
|
|
3785
|
+
blockId: block.id,
|
|
3786
|
+
status: "pending",
|
|
3787
|
+
attempts: 0,
|
|
3788
|
+
lastError: null,
|
|
3789
|
+
nextRetryAt: null,
|
|
3790
|
+
updatedAt
|
|
3791
|
+
});
|
|
3663
3792
|
return block;
|
|
3664
3793
|
});
|
|
3665
3794
|
}
|
|
3795
|
+
async processBlock(block, options) {
|
|
3796
|
+
if (block.processingStatus === "ready") return [];
|
|
3797
|
+
const summary = this.summaryJobs.get(block.id);
|
|
3798
|
+
if (!summary || summary.status !== "succeeded") {
|
|
3799
|
+
if (!this.summarizer || !this.jobCanRun(summary, options.retryFailed)) return [];
|
|
3800
|
+
const claimed = await this.commitMutation(() => {
|
|
3801
|
+
const current = this.summaryJobs.get(block.id);
|
|
3802
|
+
if (!current || !this.jobCanRun(current, options.retryFailed)) return false;
|
|
3803
|
+
this.summaryJobs.set(block.id, {
|
|
3804
|
+
...current,
|
|
3805
|
+
status: "running",
|
|
3806
|
+
attempts: current.attempts + 1,
|
|
3807
|
+
lastError: null,
|
|
3808
|
+
nextRetryAt: null,
|
|
3809
|
+
updatedAt: toUtc8Iso(this.now())
|
|
3810
|
+
});
|
|
3811
|
+
return true;
|
|
3812
|
+
});
|
|
3813
|
+
if (!claimed) return [];
|
|
3814
|
+
try {
|
|
3815
|
+
const generated = await this.summarizer(block.l5Raw);
|
|
3816
|
+
if (!generated.l0Title.trim() || !generated.l1Summary.trim() || !Array.isArray(generated.l0Tags) || !Array.isArray(generated.l2Keypoints) || typeof generated.shouldExtract !== "boolean") {
|
|
3817
|
+
throw new Error("Block summarizer returned invalid L0-L2 layers");
|
|
3818
|
+
}
|
|
3819
|
+
await this.commitMutation(() => {
|
|
3820
|
+
block.l0Title = generated.l0Title;
|
|
3821
|
+
block.l0Tags = [...generated.l0Tags];
|
|
3822
|
+
block.l1Summary = generated.l1Summary;
|
|
3823
|
+
block.l2Keypoints = [...generated.l2Keypoints];
|
|
3824
|
+
block.shouldExtract = generated.shouldExtract;
|
|
3825
|
+
const current = this.summaryJobs.get(block.id);
|
|
3826
|
+
if (!current) throw new Error(`Missing summary job for block: ${block.id}`);
|
|
3827
|
+
this.summaryJobs.set(block.id, {
|
|
3828
|
+
...current,
|
|
3829
|
+
status: "succeeded",
|
|
3830
|
+
lastError: null,
|
|
3831
|
+
nextRetryAt: null,
|
|
3832
|
+
updatedAt: toUtc8Iso(this.now())
|
|
3833
|
+
});
|
|
3834
|
+
});
|
|
3835
|
+
} catch (error) {
|
|
3836
|
+
await this.failSummary(block.id, error);
|
|
3837
|
+
return [];
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
if (block.shouldExtract === false) {
|
|
3841
|
+
await this.commitMutation(() => {
|
|
3842
|
+
const now = toUtc8Iso(this.now());
|
|
3843
|
+
this.extractionJobs.set(block.id, {
|
|
3844
|
+
blockId: block.id,
|
|
3845
|
+
status: "skipped",
|
|
3846
|
+
attempts: this.extractionJobs.get(block.id)?.attempts ?? 0,
|
|
3847
|
+
lastError: null,
|
|
3848
|
+
nextRetryAt: null,
|
|
3849
|
+
updatedAt: now
|
|
3850
|
+
});
|
|
3851
|
+
this.markBlockReady(block);
|
|
3852
|
+
});
|
|
3853
|
+
return [];
|
|
3854
|
+
}
|
|
3855
|
+
try {
|
|
3856
|
+
const extracted = await this.extractEligibleBlock({ blockId: block.id, retryFailed: options.retryFailed });
|
|
3857
|
+
return extracted ?? [];
|
|
3858
|
+
} catch {
|
|
3859
|
+
return [];
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
jobCanRun(job, force) {
|
|
3863
|
+
if (!job || job.attempts >= DERIVATION_MAX_ATTEMPTS || job.status === "running" || job.status === "succeeded") return false;
|
|
3864
|
+
return force || job.nextRetryAt === null || Date.parse(job.nextRetryAt) <= this.now().getTime();
|
|
3865
|
+
}
|
|
3866
|
+
async failSummary(blockId, error) {
|
|
3867
|
+
await this.commitMutation(() => {
|
|
3868
|
+
const job = this.summaryJobs.get(blockId);
|
|
3869
|
+
if (!job) return;
|
|
3870
|
+
this.summaryJobs.set(blockId, {
|
|
3871
|
+
...job,
|
|
3872
|
+
status: "failed",
|
|
3873
|
+
lastError: errorMessage(error),
|
|
3874
|
+
nextRetryAt: this.retryAt(job.attempts),
|
|
3875
|
+
updatedAt: toUtc8Iso(this.now())
|
|
3876
|
+
});
|
|
3877
|
+
});
|
|
3878
|
+
}
|
|
3879
|
+
retryAt(attempts) {
|
|
3880
|
+
if (attempts >= DERIVATION_MAX_ATTEMPTS) return null;
|
|
3881
|
+
return toUtc8Iso(new Date(this.now().getTime() + DERIVATION_BACKOFF_MS * 2 ** Math.max(0, attempts - 1)));
|
|
3882
|
+
}
|
|
3883
|
+
markBlockReady(block) {
|
|
3884
|
+
if (!block.l0Title || !block.l0Tags || !block.l1Summary || !block.l2Keypoints || typeof block.shouldExtract !== "boolean") {
|
|
3885
|
+
throw new Error(`Block ${block.id} cannot become ready without validated L0-L2 layers`);
|
|
3886
|
+
}
|
|
3887
|
+
const ready = this.threadBlocks(block.threadId).filter((candidate) => candidate.processingStatus === "ready");
|
|
3888
|
+
block.processingStatus = "ready";
|
|
3889
|
+
block.pointerCurrentLevel = 5;
|
|
3890
|
+
block.pointerAnchorLevel = 5;
|
|
3891
|
+
block.pointerAnchorBlockPosition = ready.length + 1;
|
|
3892
|
+
}
|
|
3666
3893
|
async extractEligibleBlock(options = {}) {
|
|
3667
|
-
if (!this.extractor
|
|
3894
|
+
if (!this.extractor) return null;
|
|
3668
3895
|
const target = this.blocks.find((block) => {
|
|
3669
|
-
if (
|
|
3896
|
+
if (block.processingStatus === "ready" || block.shouldExtract !== true) return false;
|
|
3670
3897
|
if (options.blockId !== void 0 && block.id !== options.blockId) return false;
|
|
3671
|
-
const
|
|
3672
|
-
return
|
|
3898
|
+
const job = this.extractionJobs.get(block.id);
|
|
3899
|
+
return job === void 0 || this.jobCanRun(job, options.retryFailed === true);
|
|
3673
3900
|
});
|
|
3674
3901
|
if (!target) return null;
|
|
3675
3902
|
const threadBlocks = this.threadBlocks(target.threadId);
|
|
3676
3903
|
const targetIndex = threadBlocks.indexOf(target);
|
|
3677
|
-
const next = threadBlocks
|
|
3678
|
-
if (!next) return null;
|
|
3904
|
+
const next = threadBlocks.slice(targetIndex + 1).find((block) => block.l2Keypoints !== void 0) ?? null;
|
|
3679
3905
|
const existing = this.extractionJobs.get(target.id);
|
|
3680
3906
|
await this.commitMutation(() => {
|
|
3681
3907
|
const currentStatus = this.extractionJobs.get(target.id)?.status;
|
|
3682
|
-
|
|
3683
|
-
if (currentStatus !== void 0 && currentStatus !== "failed" && !canRetrySkipped) {
|
|
3908
|
+
if (currentStatus !== void 0 && currentStatus !== "failed") {
|
|
3684
3909
|
throw new Error(`Extraction block ${target.id} is already ${currentStatus}`);
|
|
3685
3910
|
}
|
|
3686
3911
|
this.extractionJobs.set(target.id, {
|
|
@@ -3688,13 +3913,14 @@ var StrataGate = class _StrataGate {
|
|
|
3688
3913
|
status: "running",
|
|
3689
3914
|
attempts: (existing?.attempts ?? 0) + 1,
|
|
3690
3915
|
lastError: null,
|
|
3916
|
+
nextRetryAt: null,
|
|
3691
3917
|
updatedAt: toUtc8Iso(this.now())
|
|
3692
3918
|
});
|
|
3693
3919
|
});
|
|
3694
3920
|
let result;
|
|
3695
3921
|
try {
|
|
3696
3922
|
result = await this.extractor({
|
|
3697
|
-
previous: threadBlocks
|
|
3923
|
+
previous: threadBlocks.slice(0, targetIndex).reverse().find((block) => block.l2Keypoints !== void 0) ?? null,
|
|
3698
3924
|
target,
|
|
3699
3925
|
next,
|
|
3700
3926
|
timeline: this.events.map((event) => ({ id: event.id, title: event.title, temporal: event.temporal }))
|
|
@@ -3707,6 +3933,7 @@ var StrataGate = class _StrataGate {
|
|
|
3707
3933
|
...job,
|
|
3708
3934
|
status: "failed",
|
|
3709
3935
|
lastError: errorMessage(error),
|
|
3936
|
+
nextRetryAt: this.retryAt(job.attempts),
|
|
3710
3937
|
updatedAt: toUtc8Iso(this.now())
|
|
3711
3938
|
});
|
|
3712
3939
|
});
|
|
@@ -3721,6 +3948,7 @@ var StrataGate = class _StrataGate {
|
|
|
3721
3948
|
...job,
|
|
3722
3949
|
status: "failed",
|
|
3723
3950
|
lastError: reason,
|
|
3951
|
+
nextRetryAt: this.retryAt(job.attempts),
|
|
3724
3952
|
updatedAt: toUtc8Iso(this.now())
|
|
3725
3953
|
});
|
|
3726
3954
|
});
|
|
@@ -3739,8 +3967,10 @@ var StrataGate = class _StrataGate {
|
|
|
3739
3967
|
...job,
|
|
3740
3968
|
status: result.shouldExtract ? "succeeded" : "skipped",
|
|
3741
3969
|
lastError: null,
|
|
3970
|
+
nextRetryAt: null,
|
|
3742
3971
|
updatedAt: toUtc8Iso(this.now())
|
|
3743
3972
|
});
|
|
3973
|
+
this.markBlockReady(target);
|
|
3744
3974
|
return extracted;
|
|
3745
3975
|
});
|
|
3746
3976
|
}
|
|
@@ -3809,6 +4039,8 @@ var StrataGate = class _StrataGate {
|
|
|
3809
4039
|
this.currentTurn = copy.currentTurn;
|
|
3810
4040
|
this.openTail.splice(0, this.openTail.length, ...copy.openTail);
|
|
3811
4041
|
this.blocks.splice(0, this.blocks.length, ...copy.blocks);
|
|
4042
|
+
this.summaryJobs.clear();
|
|
4043
|
+
for (const job of copy.summaryJobs) this.summaryJobs.set(job.blockId, job);
|
|
3812
4044
|
this.events.splice(0, this.events.length, ...copy.events);
|
|
3813
4045
|
this.graphNodes.splice(0, this.graphNodes.length, ...copy.graphNodes);
|
|
3814
4046
|
this.graphEdges.splice(0, this.graphEdges.length, ...copy.graphEdges);
|
|
@@ -3855,6 +4087,9 @@ var StrataGate = class _StrataGate {
|
|
|
3855
4087
|
for (const job of this.extractionJobs.values()) {
|
|
3856
4088
|
if (!blockIds.has(job.blockId)) throw new Error(`Unknown extraction job block in snapshot: ${job.blockId}`);
|
|
3857
4089
|
}
|
|
4090
|
+
for (const job of this.summaryJobs.values()) {
|
|
4091
|
+
if (!blockIds.has(job.blockId)) throw new Error(`Unknown summary job block in snapshot: ${job.blockId}`);
|
|
4092
|
+
}
|
|
3858
4093
|
const elementIds = /* @__PURE__ */ new Set();
|
|
3859
4094
|
for (const element of this.elements) {
|
|
3860
4095
|
if (elementIds.has(element.id)) throw new Error(`Duplicate element ID in snapshot: ${element.id}`);
|
|
@@ -4083,7 +4318,7 @@ function extractorPayload(context) {
|
|
|
4083
4318
|
}
|
|
4084
4319
|
var JSON_RESPONSE_ATTEMPTS = 2;
|
|
4085
4320
|
var JSON_RETRY_INSTRUCTION = "Your previous response did not make one valid call to the requested tool. Do not spend output on analysis or reasoning. Immediately call that tool exactly once with complete arguments. Do not return an answer as text or markdown.";
|
|
4086
|
-
var
|
|
4321
|
+
var DEFAULT_STRUCTURED_TIMEOUT_MS = 45e3;
|
|
4087
4322
|
var STRUCTURED_FIELDS = {
|
|
4088
4323
|
summarizer: ["l0Title", "l0Tags", "l1Summary", "l2Keypoints", "shouldExtract"],
|
|
4089
4324
|
extractor: ["shouldExtract", "reason", "events"],
|
|
@@ -4234,11 +4469,15 @@ var DshModelBridge = class {
|
|
|
4234
4469
|
constructor(ctx, config) {
|
|
4235
4470
|
this.ctx = ctx;
|
|
4236
4471
|
this.config = config;
|
|
4472
|
+
this.ctx.on?.("llm/adapters-updated", () => {
|
|
4473
|
+
this.offCapabilities.clear();
|
|
4474
|
+
});
|
|
4237
4475
|
}
|
|
4238
4476
|
ctx;
|
|
4239
4477
|
config;
|
|
4240
4478
|
sessions = new AsyncLocalStorage();
|
|
4241
4479
|
successfulResponses = [];
|
|
4480
|
+
offCapabilities = /* @__PURE__ */ new Map();
|
|
4242
4481
|
run(session, operation) {
|
|
4243
4482
|
return this.sessions.run(session, operation);
|
|
4244
4483
|
}
|
|
@@ -4253,7 +4492,7 @@ var DshModelBridge = class {
|
|
|
4253
4492
|
{ messages }
|
|
4254
4493
|
));
|
|
4255
4494
|
return {
|
|
4256
|
-
l0Title: text2(raw.l0Title
|
|
4495
|
+
l0Title: text2(raw.l0Title).slice(0, 120),
|
|
4257
4496
|
l0Tags: strings2(raw.l0Tags).slice(0, 12),
|
|
4258
4497
|
l1Summary: text2(raw.l1Summary).slice(0, 2e3),
|
|
4259
4498
|
l2Keypoints: strings2(raw.l2Keypoints).slice(0, 20),
|
|
@@ -4385,10 +4624,11 @@ var DshModelBridge = class {
|
|
|
4385
4624
|
async callStructured(kind, system, payload) {
|
|
4386
4625
|
const session = this.sessions.getStore();
|
|
4387
4626
|
if (!session) throw new Error("StrataGate model callback ran without a DSH session");
|
|
4388
|
-
const
|
|
4627
|
+
const baseRoute = this.resolveRoute(session);
|
|
4628
|
+
const routeKey = `${baseRoute.provider}\0${baseRoute.model}`;
|
|
4629
|
+
let useOff = await this.shouldUseOff(baseRoute);
|
|
4389
4630
|
let lastError;
|
|
4390
4631
|
let lastResponse = "";
|
|
4391
|
-
let retryMaxTokens = this.config.maxOutputTokens;
|
|
4392
4632
|
for (let attempt = 1; attempt <= JSON_RESPONSE_ATTEMPTS; attempt += 1) {
|
|
4393
4633
|
const message = createUserMessage({
|
|
4394
4634
|
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
@@ -4396,7 +4636,8 @@ var DshModelBridge = class {
|
|
|
4396
4636
|
});
|
|
4397
4637
|
const assembler = new BlockAssembler();
|
|
4398
4638
|
const request = {
|
|
4399
|
-
...
|
|
4639
|
+
...baseRoute,
|
|
4640
|
+
...useOff ? { reasoningEffort: "off" } : {},
|
|
4400
4641
|
messages: [message],
|
|
4401
4642
|
system: attempt === 1 ? system : `${system}
|
|
4402
4643
|
|
|
@@ -4410,15 +4651,35 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
4410
4651
|
type: "function",
|
|
4411
4652
|
function: { name: STRUCTURED_TOOLS[kind].name }
|
|
4412
4653
|
},
|
|
4413
|
-
maxTokens:
|
|
4654
|
+
maxTokens: this.config.maxOutputTokens,
|
|
4414
4655
|
sessionId: session.id,
|
|
4415
4656
|
purpose: "compaction"
|
|
4416
4657
|
};
|
|
4417
|
-
|
|
4658
|
+
try {
|
|
4659
|
+
await this.consumeStructuredStream(request, assembler);
|
|
4660
|
+
} catch (error) {
|
|
4661
|
+
if (useOff && isOffRejection(error)) {
|
|
4662
|
+
this.offCapabilities.set(routeKey, "unsupported");
|
|
4663
|
+
useOff = false;
|
|
4664
|
+
this.ctx.logger.warn(`stratagate-memory ${baseRoute.provider}/${baseRoute.model} rejected reasoningEffort=off; retrying once without it`);
|
|
4665
|
+
attempt -= 1;
|
|
4666
|
+
continue;
|
|
4667
|
+
}
|
|
4668
|
+
throw error;
|
|
4669
|
+
}
|
|
4418
4670
|
const finish = assembler.finish;
|
|
4419
4671
|
if (finish.kind === "error" || finish.kind === "aborted") {
|
|
4420
|
-
|
|
4672
|
+
const failure = new Error(`StrataGate model call failed [${finish.failure.code}]: ${finish.failure.message}`);
|
|
4673
|
+
if (useOff && isOffRejection(finish.failure)) {
|
|
4674
|
+
this.offCapabilities.set(routeKey, "unsupported");
|
|
4675
|
+
useOff = false;
|
|
4676
|
+
this.ctx.logger.warn(`stratagate-memory ${baseRoute.provider}/${baseRoute.model} rejected reasoningEffort=off; retrying once without it`);
|
|
4677
|
+
attempt -= 1;
|
|
4678
|
+
continue;
|
|
4679
|
+
}
|
|
4680
|
+
throw failure;
|
|
4421
4681
|
}
|
|
4682
|
+
if (useOff) this.offCapabilities.set(routeKey, "supported");
|
|
4422
4683
|
const blocks = assembler.blocks();
|
|
4423
4684
|
const calls = blocks.filter((block) => block.type === "tool-call");
|
|
4424
4685
|
const responseForError = `${renderBlocksForDiagnostics(blocks, finish.kind)}
|
|
@@ -4454,6 +4715,15 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
4454
4715
|
{ response: responseForError }
|
|
4455
4716
|
);
|
|
4456
4717
|
}
|
|
4718
|
+
if (kind === "summarizer") {
|
|
4719
|
+
const summary = object(parsed);
|
|
4720
|
+
if (!text2(summary.l0Title) || !text2(summary.l1Summary)) {
|
|
4721
|
+
throw new ModelJsonResponseError(
|
|
4722
|
+
`StrataGate ${expectedTool} arguments were invalid: l0Title and l1Summary must not be empty`,
|
|
4723
|
+
{ response: responseForError }
|
|
4724
|
+
);
|
|
4725
|
+
}
|
|
4726
|
+
}
|
|
4457
4727
|
this.successfulResponses.push({
|
|
4458
4728
|
id: `model_response_${crypto.randomUUID()}`,
|
|
4459
4729
|
kind,
|
|
@@ -4468,7 +4738,6 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
4468
4738
|
`StrataGate ${STRUCTURED_TOOLS[kind].name} call was truncated before valid arguments`,
|
|
4469
4739
|
{ cause: error, response: responseForError }
|
|
4470
4740
|
) : error;
|
|
4471
|
-
if (finish.kind === "max-tokens") retryMaxTokens = Math.max(this.config.maxOutputTokens, RETRY_MAX_TOKENS);
|
|
4472
4741
|
if (attempt < JSON_RESPONSE_ATTEMPTS) {
|
|
4473
4742
|
this.ctx.logger.warn(`stratagate-memory model returned an invalid structured tool call; retrying (${attempt}/${JSON_RESPONSE_ATTEMPTS})`);
|
|
4474
4743
|
}
|
|
@@ -4479,25 +4748,77 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
4479
4748
|
{ cause: lastError, response: lastResponse }
|
|
4480
4749
|
);
|
|
4481
4750
|
}
|
|
4482
|
-
|
|
4483
|
-
const
|
|
4484
|
-
const
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4751
|
+
async shouldUseOff(route) {
|
|
4752
|
+
const key = `${route.provider}\0${route.model}`;
|
|
4753
|
+
const cached = this.offCapabilities.get(key);
|
|
4754
|
+
if (cached) return cached === "supported";
|
|
4755
|
+
if (typeof this.ctx.llm.resolveModelInfo !== "function") return true;
|
|
4756
|
+
const controller = new AbortController();
|
|
4757
|
+
const lookupTimeoutMs = Math.min(5e3, this.config.structuredTaskTimeoutMs ?? DEFAULT_STRUCTURED_TIMEOUT_MS);
|
|
4758
|
+
let timer;
|
|
4759
|
+
try {
|
|
4760
|
+
const info = await Promise.race([
|
|
4761
|
+
this.ctx.llm.resolveModelInfo(route.provider, route.model, controller.signal),
|
|
4762
|
+
new Promise((_resolve, reject) => {
|
|
4763
|
+
timer = setTimeout(() => {
|
|
4764
|
+
controller.abort();
|
|
4765
|
+
reject(new Error(`Model capability lookup timed out after ${lookupTimeoutMs}ms`));
|
|
4766
|
+
}, lookupTimeoutMs);
|
|
4767
|
+
timer.unref?.();
|
|
4768
|
+
})
|
|
4769
|
+
]);
|
|
4770
|
+
if (!info.reasoning) return true;
|
|
4771
|
+
const supported = info.reasoning.efforts.some(({ id }) => String(id) === "off");
|
|
4772
|
+
this.offCapabilities.set(key, supported ? "supported" : "unsupported");
|
|
4773
|
+
return supported;
|
|
4774
|
+
} catch {
|
|
4775
|
+
return true;
|
|
4776
|
+
} finally {
|
|
4777
|
+
if (timer) clearTimeout(timer);
|
|
4778
|
+
}
|
|
4779
|
+
}
|
|
4780
|
+
async consumeStructuredStream(request, assembler) {
|
|
4781
|
+
const timeoutMs = this.config.structuredTaskTimeoutMs ?? DEFAULT_STRUCTURED_TIMEOUT_MS;
|
|
4782
|
+
const controller = new AbortController();
|
|
4783
|
+
const timedRequest = { ...request, signal: controller.signal };
|
|
4784
|
+
let timer;
|
|
4785
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
4786
|
+
timer = setTimeout(() => {
|
|
4787
|
+
controller.abort(new Error(`StrataGate structured model task timed out after ${timeoutMs}ms`));
|
|
4788
|
+
reject(new Error(`StrataGate structured model task timed out after ${timeoutMs}ms`));
|
|
4789
|
+
}, timeoutMs);
|
|
4790
|
+
timer.unref?.();
|
|
4488
4791
|
});
|
|
4792
|
+
try {
|
|
4793
|
+
await Promise.race([
|
|
4794
|
+
(async () => {
|
|
4795
|
+
for await (const chunk of this.ctx.llm.stream(timedRequest)) assembler.push(chunk);
|
|
4796
|
+
})(),
|
|
4797
|
+
timeout
|
|
4798
|
+
]);
|
|
4799
|
+
} finally {
|
|
4800
|
+
if (timer) clearTimeout(timer);
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
resolveRoute(session) {
|
|
4804
|
+
const request = session.requestHeader()?.config;
|
|
4489
4805
|
if (this.config.provider && this.config.model) {
|
|
4490
|
-
return
|
|
4806
|
+
return { provider: this.config.provider, model: this.config.model };
|
|
4491
4807
|
}
|
|
4492
|
-
if (request) return
|
|
4808
|
+
if (request) return { provider: request.provider, model: request.model };
|
|
4493
4809
|
const fallback = this.ctx.agentDefaultModel.currentSelection();
|
|
4494
|
-
return {
|
|
4495
|
-
provider: fallback.provider,
|
|
4496
|
-
model: fallback.model,
|
|
4497
|
-
...structured ? { reasoningEffort: "off" } : fallback.reasoningEffort !== void 0 ? { reasoningEffort: fallback.reasoningEffort } : {}
|
|
4498
|
-
};
|
|
4810
|
+
return { provider: fallback.provider, model: fallback.model };
|
|
4499
4811
|
}
|
|
4500
4812
|
};
|
|
4813
|
+
function isOffRejection(error) {
|
|
4814
|
+
let detail;
|
|
4815
|
+
try {
|
|
4816
|
+
detail = typeof error === "string" ? error : error && typeof error === "object" ? JSON.stringify(error, Object.getOwnPropertyNames(error)) : String(error);
|
|
4817
|
+
} catch {
|
|
4818
|
+
detail = error instanceof Error ? error.message : String(error);
|
|
4819
|
+
}
|
|
4820
|
+
return /(?:reasoning[_ -]?effort|reasoning).{0,100}\boff\b|\boff\b.{0,100}(?:reasoning[_ -]?effort|reasoning)/iu.test(detail) && /(?:unsupported|not supported|invalid|not allowed|unknown|unrecognized|reject|must be|expected)/iu.test(detail);
|
|
4821
|
+
}
|
|
4501
4822
|
|
|
4502
4823
|
// src/runtime.ts
|
|
4503
4824
|
import { createHash } from "node:crypto";
|
|
@@ -4643,6 +4964,17 @@ var DshMetadataStore = class {
|
|
|
4643
4964
|
this.database = new DatabaseSync2(filename);
|
|
4644
4965
|
this.database.exec(METADATA_SCHEMA);
|
|
4645
4966
|
}
|
|
4967
|
+
blockTurnSize() {
|
|
4968
|
+
const row = this.database.prepare("SELECT value FROM stratagate_dsh_settings WHERE key = 'blockTurnSize'").get();
|
|
4969
|
+
const value = Number(row?.value);
|
|
4970
|
+
return Number.isSafeInteger(value) && value >= 1 ? value : null;
|
|
4971
|
+
}
|
|
4972
|
+
setBlockTurnSize(value) {
|
|
4973
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
4974
|
+
throw new TypeError("blockTurnSize must be a positive integer");
|
|
4975
|
+
}
|
|
4976
|
+
this.setSetting("blockTurnSize", value);
|
|
4977
|
+
}
|
|
4646
4978
|
blockDecayLambda() {
|
|
4647
4979
|
const row = this.database.prepare("SELECT value FROM stratagate_dsh_settings WHERE key = 'blockDecayLambda'").get();
|
|
4648
4980
|
const value = Number(row?.value);
|
|
@@ -4652,11 +4984,14 @@ var DshMetadataStore = class {
|
|
|
4652
4984
|
if (!Number.isFinite(value) || value < 0) {
|
|
4653
4985
|
throw new TypeError("blockDecayLambda must be a non-negative finite number");
|
|
4654
4986
|
}
|
|
4987
|
+
this.setSetting("blockDecayLambda", value);
|
|
4988
|
+
}
|
|
4989
|
+
setSetting(key, value) {
|
|
4655
4990
|
this.database.prepare(`
|
|
4656
4991
|
INSERT INTO stratagate_dsh_settings (key, value, updated_at)
|
|
4657
|
-
VALUES (
|
|
4992
|
+
VALUES (?, ?, ?)
|
|
4658
4993
|
ON CONFLICT (key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at
|
|
4659
|
-
`).run(String(value), (/* @__PURE__ */ new Date()).toISOString());
|
|
4994
|
+
`).run(key, String(value), (/* @__PURE__ */ new Date()).toISOString());
|
|
4660
4995
|
}
|
|
4661
4996
|
workspaceName(namespace) {
|
|
4662
4997
|
const row = this.database.prepare("SELECT display_name FROM stratagate_dsh_workspaces WHERE namespace = ?").get(namespace);
|
|
@@ -4697,6 +5032,7 @@ var StrataGateRuntime = class {
|
|
|
4697
5032
|
this.models = models;
|
|
4698
5033
|
this.onIngestError = onIngestError;
|
|
4699
5034
|
this.flushNativeSession = flushNativeSession;
|
|
5035
|
+
this.blockTurnSize = config.blockTurnSize;
|
|
4700
5036
|
this.blockDecayLambda = config.blockDecayLambda;
|
|
4701
5037
|
}
|
|
4702
5038
|
config;
|
|
@@ -4709,11 +5045,14 @@ var StrataGateRuntime = class {
|
|
|
4709
5045
|
latestBatchIds = /* @__PURE__ */ new Map();
|
|
4710
5046
|
workspaceNames = /* @__PURE__ */ new Map();
|
|
4711
5047
|
migrationTimers = /* @__PURE__ */ new Map();
|
|
5048
|
+
derivationTimers = /* @__PURE__ */ new Map();
|
|
5049
|
+
derivationRuns = /* @__PURE__ */ new Map();
|
|
4712
5050
|
ingestTail = Promise.resolve();
|
|
4713
5051
|
settingsTail = Promise.resolve();
|
|
4714
5052
|
batchSequence = 0;
|
|
4715
5053
|
closed = false;
|
|
4716
5054
|
ingestError;
|
|
5055
|
+
blockTurnSize;
|
|
4717
5056
|
blockDecayLambda;
|
|
4718
5057
|
acceptEvent(session, event) {
|
|
4719
5058
|
if (this.closed) return;
|
|
@@ -4724,15 +5063,8 @@ var StrataGateRuntime = class {
|
|
|
4724
5063
|
}).then(async () => {
|
|
4725
5064
|
const memory = await this.space(session);
|
|
4726
5065
|
try {
|
|
4727
|
-
const result = await
|
|
4728
|
-
if (result.sealedBlock)
|
|
4729
|
-
const contexts = memory.getBlockContext(String(session.id));
|
|
4730
|
-
const sealedContext = contexts.find(({ id }) => id === result.sealedBlock.id);
|
|
4731
|
-
if (!sealedContext) throw new Error(`Missing context for sealed StrataGate block ${result.sealedBlock.id}`);
|
|
4732
|
-
this.replaceSealedSurface(session, result.sealedBlock, sealedContext, turn.dshTurn);
|
|
4733
|
-
this.syncDecayedBlockSurface(session, contexts);
|
|
4734
|
-
await this.flushNativeSession(session);
|
|
4735
|
-
}
|
|
5066
|
+
const result = await memory.appendTurn(turn, { deferDerivation: true });
|
|
5067
|
+
if (result.sealedBlock) this.scheduleBlockDerivation(session, memory);
|
|
4736
5068
|
} finally {
|
|
4737
5069
|
await this.persistSuccessfulResponses(memory);
|
|
4738
5070
|
}
|
|
@@ -5046,6 +5378,8 @@ var StrataGateRuntime = class {
|
|
|
5046
5378
|
this.closed = true;
|
|
5047
5379
|
for (const timer of this.migrationTimers.values()) clearTimeout(timer);
|
|
5048
5380
|
this.migrationTimers.clear();
|
|
5381
|
+
for (const timer of this.derivationTimers.values()) clearTimeout(timer);
|
|
5382
|
+
this.derivationTimers.clear();
|
|
5049
5383
|
let flushError;
|
|
5050
5384
|
try {
|
|
5051
5385
|
await this.flush();
|
|
@@ -5053,6 +5387,7 @@ var StrataGateRuntime = class {
|
|
|
5053
5387
|
flushError = error;
|
|
5054
5388
|
}
|
|
5055
5389
|
const settled = await Promise.allSettled(this.spaces.values());
|
|
5390
|
+
await Promise.allSettled(this.derivationRuns.values());
|
|
5056
5391
|
await Promise.all(settled.flatMap((result) => result.status === "fulfilled" ? [result.value.close()] : []));
|
|
5057
5392
|
if (flushError !== void 0) throw flushError;
|
|
5058
5393
|
}
|
|
@@ -5075,6 +5410,7 @@ var StrataGateRuntime = class {
|
|
|
5075
5410
|
if (this.config.database === ":memory:" || !existsSync(this.config.database)) return;
|
|
5076
5411
|
const metadata = new DshMetadataStore(this.config.database);
|
|
5077
5412
|
try {
|
|
5413
|
+
this.blockTurnSize = metadata.blockTurnSize() ?? this.config.blockTurnSize;
|
|
5078
5414
|
this.blockDecayLambda = metadata.blockDecayLambda() ?? this.config.blockDecayLambda;
|
|
5079
5415
|
} finally {
|
|
5080
5416
|
metadata.close();
|
|
@@ -5083,10 +5419,10 @@ var StrataGateRuntime = class {
|
|
|
5083
5419
|
try {
|
|
5084
5420
|
for (const namespace of storage.listNamespaces()) {
|
|
5085
5421
|
const loaded = await storage.load(namespace);
|
|
5086
|
-
if (!loaded || loaded.snapshot.blockTurnSize === this.
|
|
5422
|
+
if (!loaded || loaded.snapshot.blockTurnSize === this.blockTurnSize && loaded.snapshot.blockDecayLambda === this.blockDecayLambda) continue;
|
|
5087
5423
|
await storage.save(namespace, {
|
|
5088
5424
|
...loaded.snapshot,
|
|
5089
|
-
blockTurnSize: this.
|
|
5425
|
+
blockTurnSize: this.blockTurnSize,
|
|
5090
5426
|
blockDecayLambda: this.blockDecayLambda
|
|
5091
5427
|
}, loaded.revision);
|
|
5092
5428
|
}
|
|
@@ -5122,7 +5458,7 @@ var StrataGateRuntime = class {
|
|
|
5122
5458
|
memory = await StrataGate.open({
|
|
5123
5459
|
database: this.config.database,
|
|
5124
5460
|
namespace: key,
|
|
5125
|
-
blockTurnSize: this.
|
|
5461
|
+
blockTurnSize: this.blockTurnSize,
|
|
5126
5462
|
blockDecayLambda: this.blockDecayLambda,
|
|
5127
5463
|
graphProjector: this.models.graphProjector,
|
|
5128
5464
|
disableElementProjection: true
|
|
@@ -5167,6 +5503,18 @@ var StrataGateRuntime = class {
|
|
|
5167
5503
|
await update;
|
|
5168
5504
|
return value;
|
|
5169
5505
|
}
|
|
5506
|
+
async adminSetBlockTurnSize(value) {
|
|
5507
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
5508
|
+
throw new TypeError("blockTurnSize must be a positive integer");
|
|
5509
|
+
}
|
|
5510
|
+
const update = this.settingsTail.catch(() => {
|
|
5511
|
+
}).then(() => this.applyBlockTurnSize(value));
|
|
5512
|
+
this.settingsTail = update.then(() => {
|
|
5513
|
+
}, () => {
|
|
5514
|
+
});
|
|
5515
|
+
await update;
|
|
5516
|
+
return value;
|
|
5517
|
+
}
|
|
5170
5518
|
async adminExpandBlock(namespace, id, target) {
|
|
5171
5519
|
const key = namespace.trim();
|
|
5172
5520
|
if (!key) throw new TypeError("StrataGate admin namespace must not be empty");
|
|
@@ -5181,7 +5529,7 @@ var StrataGateRuntime = class {
|
|
|
5181
5529
|
const memory = await StrataGate.open({
|
|
5182
5530
|
database: this.config.database,
|
|
5183
5531
|
namespace: key,
|
|
5184
|
-
blockTurnSize: this.
|
|
5532
|
+
blockTurnSize: this.blockTurnSize,
|
|
5185
5533
|
blockDecayLambda: this.blockDecayLambda,
|
|
5186
5534
|
summarizer: this.models.summarizer,
|
|
5187
5535
|
extractor: this.models.extractor,
|
|
@@ -5230,6 +5578,37 @@ var StrataGateRuntime = class {
|
|
|
5230
5578
|
}
|
|
5231
5579
|
}
|
|
5232
5580
|
}
|
|
5581
|
+
async applyBlockTurnSize(value) {
|
|
5582
|
+
await this.flush();
|
|
5583
|
+
this.blockTurnSize = value;
|
|
5584
|
+
if (this.config.database !== ":memory:") {
|
|
5585
|
+
const metadata = new DshMetadataStore(this.config.database);
|
|
5586
|
+
try {
|
|
5587
|
+
metadata.setBlockTurnSize(value);
|
|
5588
|
+
} finally {
|
|
5589
|
+
metadata.close();
|
|
5590
|
+
}
|
|
5591
|
+
}
|
|
5592
|
+
const openNamespaces = /* @__PURE__ */ new Set();
|
|
5593
|
+
for (const [namespace, opening] of this.spaces) {
|
|
5594
|
+
const memory = await opening;
|
|
5595
|
+
await memory.setBlockTurnSize(value);
|
|
5596
|
+
openNamespaces.add(namespace);
|
|
5597
|
+
}
|
|
5598
|
+
if (this.config.database !== ":memory:" && existsSync(this.config.database)) {
|
|
5599
|
+
const storage = new SqliteStorage({ filename: this.config.database });
|
|
5600
|
+
try {
|
|
5601
|
+
for (const namespace of storage.listNamespaces()) {
|
|
5602
|
+
if (openNamespaces.has(namespace)) continue;
|
|
5603
|
+
const loaded = await storage.load(namespace);
|
|
5604
|
+
if (!loaded || loaded.snapshot.blockTurnSize === value) continue;
|
|
5605
|
+
await storage.save(namespace, { ...loaded.snapshot, blockTurnSize: value }, loaded.revision);
|
|
5606
|
+
}
|
|
5607
|
+
} finally {
|
|
5608
|
+
await storage.close();
|
|
5609
|
+
}
|
|
5610
|
+
}
|
|
5611
|
+
}
|
|
5233
5612
|
space(session) {
|
|
5234
5613
|
const namespace = this.namespaceFor(session);
|
|
5235
5614
|
this.rememberWorkspace(namespace, session.header.cwd);
|
|
@@ -5238,7 +5617,7 @@ var StrataGateRuntime = class {
|
|
|
5238
5617
|
opening = StrataGate.open({
|
|
5239
5618
|
database: this.config.database,
|
|
5240
5619
|
namespace,
|
|
5241
|
-
blockTurnSize: this.
|
|
5620
|
+
blockTurnSize: this.blockTurnSize,
|
|
5242
5621
|
blockDecayLambda: this.blockDecayLambda,
|
|
5243
5622
|
summarizer: this.models.summarizer,
|
|
5244
5623
|
extractor: this.models.extractor,
|
|
@@ -5247,23 +5626,14 @@ var StrataGateRuntime = class {
|
|
|
5247
5626
|
}).then(async (memory) => {
|
|
5248
5627
|
try {
|
|
5249
5628
|
try {
|
|
5250
|
-
|
|
5629
|
+
await memory.resumePendingWork({ deferDerivation: true, threadId: String(session.id) });
|
|
5251
5630
|
const contexts = memory.getBlockContext(String(session.id));
|
|
5252
|
-
for (const block of resumed.sealedBlocks) {
|
|
5253
|
-
if (block.threadId !== String(session.id)) continue;
|
|
5254
|
-
const endTurn = dshTurnAtBlockEnd(session, block);
|
|
5255
|
-
const context = contexts.find(({ id }) => id === block.id);
|
|
5256
|
-
if (!context) throw new Error(`Missing context for recovered StrataGate block ${block.id}`);
|
|
5257
|
-
this.replaceSealedSurface(session, block, context, endTurn);
|
|
5258
|
-
}
|
|
5259
5631
|
this.syncDecayedBlockSurface(session, contexts);
|
|
5260
|
-
if (resumed.sealedBlocks.some((block) => block.threadId === String(session.id))) {
|
|
5261
|
-
await this.flushNativeSession(session);
|
|
5262
|
-
}
|
|
5263
5632
|
} finally {
|
|
5264
5633
|
await this.persistSuccessfulResponses(memory);
|
|
5265
5634
|
}
|
|
5266
5635
|
this.scheduleGraphMigration(session, memory);
|
|
5636
|
+
this.scheduleBlockDerivation(session, memory);
|
|
5267
5637
|
return memory;
|
|
5268
5638
|
} catch (error) {
|
|
5269
5639
|
await memory.close().catch(() => {
|
|
@@ -5297,6 +5667,43 @@ var StrataGateRuntime = class {
|
|
|
5297
5667
|
target: { eventIds: [.../* @__PURE__ */ new Set([...node.sourceEventIds, ...edges.flatMap(({ sourceEventIds }) => sourceEventIds)])], elementIds: [] }
|
|
5298
5668
|
}], { node, edges });
|
|
5299
5669
|
}
|
|
5670
|
+
scheduleBlockDerivation(session, memory) {
|
|
5671
|
+
const threadId = String(session.id);
|
|
5672
|
+
const key = `${this.namespaceFor(session)}\0${threadId}`;
|
|
5673
|
+
if (this.closed || this.derivationTimers.has(key) || this.derivationRuns.has(key)) return;
|
|
5674
|
+
const pendingBlockIds = new Set(memory.listBlocks().filter((block) => block.threadId === threadId && block.processingStatus === "pending").map((block) => block.id));
|
|
5675
|
+
if (pendingBlockIds.size === 0) return;
|
|
5676
|
+
const retryTimes = [
|
|
5677
|
+
...memory.listSummaryJobs(),
|
|
5678
|
+
...memory.listExtractionJobs()
|
|
5679
|
+
].filter((job) => pendingBlockIds.has(job.blockId) && (job.status === "pending" || job.status === "failed" && job.nextRetryAt !== null)).map((job) => job.nextRetryAt ? Date.parse(job.nextRetryAt) : Date.now()).filter(Number.isFinite);
|
|
5680
|
+
if (retryTimes.length === 0) return;
|
|
5681
|
+
const delay = Math.max(0, Math.min(...retryTimes) - Date.now());
|
|
5682
|
+
const timer = setTimeout(() => {
|
|
5683
|
+
this.derivationTimers.delete(key);
|
|
5684
|
+
if (this.closed) return;
|
|
5685
|
+
const run = this.models.run(session, () => memory.resumePendingWork({ threadId })).then(async (resumed) => {
|
|
5686
|
+
await this.persistSuccessfulResponses(memory);
|
|
5687
|
+
const contexts = memory.getBlockContext(threadId);
|
|
5688
|
+
for (const block of resumed.readyBlocks) {
|
|
5689
|
+
if (block.threadId !== threadId) continue;
|
|
5690
|
+
const context = contexts.find(({ id }) => id === block.id);
|
|
5691
|
+
if (!context) throw new Error(`Missing context for ready StrataGate block ${block.id}`);
|
|
5692
|
+
this.replaceSealedSurface(session, block, context, dshTurnAtBlockEnd(session, block));
|
|
5693
|
+
}
|
|
5694
|
+
const changed = this.syncDecayedBlockSurface(session, contexts);
|
|
5695
|
+
if (resumed.readyBlocks.length > 0 || changed) await this.flushNativeSession(session);
|
|
5696
|
+
}).catch((error) => {
|
|
5697
|
+
this.onIngestError(error);
|
|
5698
|
+
}).finally(() => {
|
|
5699
|
+
this.derivationRuns.delete(key);
|
|
5700
|
+
this.scheduleBlockDerivation(session, memory);
|
|
5701
|
+
});
|
|
5702
|
+
this.derivationRuns.set(key, run);
|
|
5703
|
+
}, delay);
|
|
5704
|
+
timer.unref?.();
|
|
5705
|
+
this.derivationTimers.set(key, timer);
|
|
5706
|
+
}
|
|
5300
5707
|
scheduleGraphMigration(session, memory) {
|
|
5301
5708
|
const namespace = this.namespaceFor(session);
|
|
5302
5709
|
if (this.closed || this.migrationTimers.has(namespace)) return;
|
|
@@ -5936,7 +6343,7 @@ function clusterKnowledgeGraph(rawNodes, rawEdges) {
|
|
|
5936
6343
|
}
|
|
5937
6344
|
|
|
5938
6345
|
// src/web.ts
|
|
5939
|
-
var STRATAGATE_DSH_VERSION = "0.2.
|
|
6346
|
+
var STRATAGATE_DSH_VERSION = "0.2.36";
|
|
5940
6347
|
var LEGACY_THREAD_ID = "__legacy__";
|
|
5941
6348
|
var nodeRequire = createRequire(import.meta.url);
|
|
5942
6349
|
function installedPackageVersion(names) {
|
|
@@ -5992,6 +6399,13 @@ function sourceMessages(snapshot, ids) {
|
|
|
5992
6399
|
return output;
|
|
5993
6400
|
}
|
|
5994
6401
|
function blockLayers(block) {
|
|
6402
|
+
if (block.processingStatus !== "ready" || !block.l0Title || !block.l0Tags || !block.l1Summary || !block.l2Keypoints) {
|
|
6403
|
+
return [
|
|
6404
|
+
{ level: 3, content: block.l3Condensed },
|
|
6405
|
+
{ level: 4, content: block.l4Readable },
|
|
6406
|
+
{ level: 5, content: block.l5Raw.map((message) => `${message.role}: ${message.content}`).join("\n\n") }
|
|
6407
|
+
];
|
|
6408
|
+
}
|
|
5995
6409
|
return [
|
|
5996
6410
|
{ level: 0, content: `${block.l0Title}
|
|
5997
6411
|
\u6807\u7B7E\uFF1A${block.l0Tags.join("\u3001") || "\u65E0"}` },
|
|
@@ -6125,12 +6539,31 @@ async function overview(runtime) {
|
|
|
6125
6539
|
};
|
|
6126
6540
|
}
|
|
6127
6541
|
async function updateSettings(runtime, url) {
|
|
6128
|
-
const
|
|
6129
|
-
const
|
|
6130
|
-
if (
|
|
6131
|
-
throw new AdminHttpError(400, "
|
|
6132
|
-
}
|
|
6133
|
-
|
|
6542
|
+
const rawTurnSize = url.searchParams.get("blockTurnSize")?.trim();
|
|
6543
|
+
const rawLambda = url.searchParams.get("blockDecayLambda")?.trim();
|
|
6544
|
+
if (rawTurnSize === void 0 && rawLambda === void 0) {
|
|
6545
|
+
throw new AdminHttpError(400, "blockTurnSize or blockDecayLambda is required");
|
|
6546
|
+
}
|
|
6547
|
+
let turnSize;
|
|
6548
|
+
let lambda;
|
|
6549
|
+
if (rawTurnSize !== void 0) {
|
|
6550
|
+
const value = Number(rawTurnSize);
|
|
6551
|
+
if (!rawTurnSize || !Number.isSafeInteger(value) || value < 1) {
|
|
6552
|
+
throw new AdminHttpError(400, "blockTurnSize must be a positive integer");
|
|
6553
|
+
}
|
|
6554
|
+
turnSize = value;
|
|
6555
|
+
}
|
|
6556
|
+
if (rawLambda !== void 0) {
|
|
6557
|
+
const value = Number(rawLambda);
|
|
6558
|
+
if (!rawLambda || !Number.isFinite(value) || value < 0) {
|
|
6559
|
+
throw new AdminHttpError(400, "blockDecayLambda must be a non-negative finite number");
|
|
6560
|
+
}
|
|
6561
|
+
lambda = value;
|
|
6562
|
+
}
|
|
6563
|
+
const result = {};
|
|
6564
|
+
if (turnSize !== void 0) result.blockTurnSize = await runtime.adminSetBlockTurnSize(turnSize);
|
|
6565
|
+
if (lambda !== void 0) result.blockDecayLambda = await runtime.adminSetBlockDecayLambda(lambda);
|
|
6566
|
+
return result;
|
|
6134
6567
|
}
|
|
6135
6568
|
async function importExternalMemory(runtime, req) {
|
|
6136
6569
|
let suppliedBody = req.body;
|