stratagate-dsh 0.2.47 → 0.2.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7099,7 +7099,7 @@ function clusterKnowledgeGraph(rawNodes, rawEdges) {
7099
7099
  }
7100
7100
 
7101
7101
  // src/web.ts
7102
- var STRATAGATE_DSH_VERSION = "0.2.36";
7102
+ var STRATAGATE_DSH_VERSION = "0.2.48";
7103
7103
  var LEGACY_THREAD_ID = "__legacy__";
7104
7104
  var nodeRequire = createRequire(import.meta.url);
7105
7105
  function installedPackageVersion(names) {
@@ -7154,23 +7154,32 @@ function sourceMessages(snapshot, ids) {
7154
7154
  }
7155
7155
  return output;
7156
7156
  }
7157
+ function withLayerMetrics(layers) {
7158
+ const tokenCounts = new Map(layers.map(({ level, content }) => [level, estimateTokens(content)]));
7159
+ const l5Tokens = tokenCounts.get(5) ?? 0;
7160
+ return layers.map((layer) => {
7161
+ const tokens = tokenCounts.get(layer.level) ?? 0;
7162
+ const percentOfL5 = layer.level === 5 ? 100 : l5Tokens > 0 ? Math.round(tokens / l5Tokens * 100) : 0;
7163
+ return { ...layer, tokens, percentOfL5 };
7164
+ });
7165
+ }
7157
7166
  function blockLayers(block) {
7158
7167
  if (block.processingStatus !== "ready" || !block.l0Title || !block.l0Tags || !block.l1Summary || !block.l2Keypoints) {
7159
- return [
7168
+ return withLayerMetrics([
7160
7169
  { level: 3, content: block.l3Condensed },
7161
7170
  { level: 4, content: block.l4Readable },
7162
7171
  { level: 5, content: block.l5Raw.map((message) => `${message.role}: ${message.content}`).join("\n\n") }
7163
- ];
7172
+ ]);
7164
7173
  }
7165
- return [
7174
+ return withLayerMetrics([
7166
7175
  { level: 0, content: `${block.l0Title}
7167
- \u6807\u7B7E\uFF1A${block.l0Tags.join("\u3001") || "\u65E0"}` },
7176
+ Tags: ${block.l0Tags.join(", ") || "none"}` },
7168
7177
  { level: 1, content: block.l1Summary || block.l0Title },
7169
- { level: 2, content: block.l2Keypoints.map((point) => `\u2022 ${point}`).join("\n") || block.l1Summary || block.l0Title },
7178
+ { level: 2, content: block.l2Keypoints.map((point) => `- ${point}`).join("\n") || block.l1Summary || block.l0Title },
7170
7179
  { level: 3, content: block.l3Condensed || block.l2Keypoints.join("\n") || block.l1Summary },
7171
7180
  { level: 4, content: block.l4Readable || block.l3Condensed },
7172
7181
  { level: 5, content: block.l5Raw.map((message) => `${message.role}: ${message.content}`).join("\n\n") }
7173
- ];
7182
+ ]);
7174
7183
  }
7175
7184
  function eventSummary(event) {
7176
7185
  return {
@@ -7393,6 +7402,15 @@ function receiptThreadId(id) {
7393
7402
  const match = /^dsh:(.+):turn:\d+$/.exec(id);
7394
7403
  return match?.[1]?.trim() || null;
7395
7404
  }
7405
+ function receiptTurnNumber(id) {
7406
+ const match = /^dsh:(.+):turn:(\d+)$/.exec(id);
7407
+ if (!match) return null;
7408
+ const turn = Number(match[2]);
7409
+ return Number.isSafeInteger(turn) ? turn : null;
7410
+ }
7411
+ function receiptTurnKey(threadId, createdAt) {
7412
+ return `${threadId}\0${timestampKey(createdAt)}`;
7413
+ }
7396
7414
  function timestampKey(value) {
7397
7415
  const parsed = Date.parse(value);
7398
7416
  return Number.isFinite(parsed) ? String(parsed) : value;
@@ -7400,11 +7418,14 @@ function timestampKey(value) {
7400
7418
  function recoverSnapshotView(snapshot) {
7401
7419
  const receiptThreads = /* @__PURE__ */ new Map();
7402
7420
  const receiptActivity = /* @__PURE__ */ new Map();
7421
+ const receiptTurns = /* @__PURE__ */ new Map();
7403
7422
  const receiptCandidates = /* @__PURE__ */ new Map();
7404
7423
  for (const receipt of snapshot.ingestionReceipts) {
7405
7424
  const threadId = receiptThreadId(receipt.id);
7406
7425
  if (!threadId) continue;
7407
7426
  receiptThreads.set(receipt.id, threadId);
7427
+ const turn = receiptTurnNumber(receipt.id);
7428
+ if (turn !== null) receiptTurns.set(receiptTurnKey(threadId, receipt.createdAt), turn);
7408
7429
  const currentActivity = receiptActivity.get(threadId);
7409
7430
  if (!currentActivity || receipt.createdAt > currentActivity) receiptActivity.set(threadId, receipt.createdAt);
7410
7431
  const key = timestampKey(receipt.createdAt);
@@ -7449,8 +7470,10 @@ function recoverSnapshotView(snapshot) {
7449
7470
  const turnCounters = /* @__PURE__ */ new Map();
7450
7471
  for (const block of blocks) {
7451
7472
  if (block.source.threadId) {
7452
- block.turnRange = [block.source.startTurn, block.source.endTurn];
7453
- turnCounters.set(block.threadId, Math.max(turnCounters.get(block.threadId) ?? 0, block.source.endTurn));
7473
+ const turnMessages = block.messages.filter(({ role }) => role === "user");
7474
+ const dshTurns = turnMessages.map((message) => receiptTurns.get(receiptTurnKey(block.threadId, message.createdAt)));
7475
+ block.turnRange = dshTurns.length > 0 && dshTurns.every((turn) => turn !== void 0) ? [Math.min(...dshTurns), Math.max(...dshTurns)] : [block.source.startTurn, block.source.endTurn];
7476
+ turnCounters.set(block.threadId, Math.max(turnCounters.get(block.threadId) ?? 0, block.turnRange[1]));
7454
7477
  continue;
7455
7478
  }
7456
7479
  const turns = Math.max(1, block.messages.filter(({ role }) => role === "user").length);
@@ -7462,7 +7485,8 @@ function recoverSnapshotView(snapshot) {
7462
7485
  blocks,
7463
7486
  openMessages: recoverMessages(snapshot.openTail),
7464
7487
  receiptThreads,
7465
- receiptActivity
7488
+ receiptActivity,
7489
+ receiptTurns
7466
7490
  };
7467
7491
  }
7468
7492
  function virtualBlockLayers(block) {
@@ -7473,14 +7497,14 @@ function virtualBlockLayers(block) {
7473
7497
  const title = firstUser?.content.replace(/\s+/g, " ").trim().slice(0, 80) || "\u65E7\u4F1A\u8BDD\u7247\u6BB5";
7474
7498
  const summary = natural.map(({ content }) => content.replace(/\s+/g, " ").trim()).filter(Boolean).join(" ").slice(0, 500);
7475
7499
  const keypoints = natural.filter(({ role }) => role === "user").map(({ content }) => content.replace(/\s+/g, " ").trim().slice(0, 160));
7476
- return [
7500
+ return withLayerMetrics([
7477
7501
  { level: 0, content: title },
7478
7502
  { level: 1, content: summary || title },
7479
7503
  { level: 2, content: keypoints.map((point) => `\u2022 ${point}`).join("\n") || summary || title },
7480
7504
  { level: 3, content: deterministic.l3Condensed },
7481
7505
  { level: 4, content: deterministic.l4Readable },
7482
7506
  { level: 5, content: block.messages.map((message) => `${message.role}: ${message.content}`).join("\n\n") }
7483
- ];
7507
+ ]);
7484
7508
  }
7485
7509
  function conversationRows(snapshot, view = recoverSnapshotView(snapshot)) {
7486
7510
  const ids = /* @__PURE__ */ new Set([
@@ -7559,7 +7583,10 @@ async function memories(runtime, url) {
7559
7583
  const scopedBlocks = activeThreadId ? recovered.blocks.filter((block) => block.threadId === activeThreadId) : [];
7560
7584
  values = scopedBlocks.map((block) => {
7561
7585
  const source = block.source;
7586
+ const layers = virtualBlockLayers(block);
7587
+ const layerTokens = layers.map(({ level, tokens, percentOfL5 }) => ({ level, tokens, percentOfL5 }));
7562
7588
  const extraction = snapshot.extractionJobs.find(({ blockId }) => blockId === source.id);
7589
+ const summary = snapshot.summaryJobs.find(({ blockId }) => blockId === source.id);
7563
7590
  const blockMessageIds = new Set(block.messages.map(({ id }) => id));
7564
7591
  const relatedEvents = snapshot.events.filter((event) => event.sourceBlockId === source.id && (!block.virtual || event.sourceMessageIds.some((id) => blockMessageIds.has(id))));
7565
7592
  const eventIds = new Set(relatedEvents.map(({ id }) => id));
@@ -7577,23 +7604,37 @@ async function memories(runtime, url) {
7577
7604
  latestBlockPosition,
7578
7605
  snapshot.blockDecayLambda
7579
7606
  );
7607
+ const currentMetrics = layerTokens.find(({ level }) => level === currentLevel);
7608
+ const l5Tokens = layerTokens.find(({ level }) => level === 5)?.tokens ?? 0;
7580
7609
  return {
7581
7610
  id: block.id,
7582
7611
  sourceBlockId: source.id,
7583
7612
  threadId: block.threadId,
7584
7613
  sequence: source.sequence,
7614
+ blockIndex: blockPosition,
7585
7615
  turnRange: block.turnRange,
7586
7616
  title: block.virtual && block.messages.length !== source.l5Raw.length ? block.messages.find(({ role }) => role === "user")?.content.replace(/\s+/g, " ").trim().slice(0, 80) || "\u65E7\u4F1A\u8BDD\u7247\u6BB5" : source.l0Title,
7587
7617
  tags: source.l0Tags,
7588
7618
  summary: source.l1Summary,
7589
7619
  keypoints: source.l2Keypoints,
7590
7620
  currentLevel,
7621
+ currentTokens: currentMetrics?.tokens ?? 0,
7622
+ l5Tokens,
7623
+ compressionPercent: currentMetrics?.percentOfL5 ?? (currentLevel === 5 ? 100 : 0),
7624
+ layerTokens,
7591
7625
  distanceFromLatest: Math.max(0, latestBlockPosition - blockPosition),
7592
7626
  expansionSource: source.lastLiftedAt ? source.lastLiftedBy ?? "legacy" : null,
7593
7627
  lastLiftedAt: source.lastLiftedAt,
7594
7628
  sourceMessages: block.messages.length,
7595
7629
  createdAt: source.createdAt,
7596
7630
  virtual: block.virtual,
7631
+ processingStatus: source.processingStatus,
7632
+ summaryJob: summary ? {
7633
+ status: summary.status,
7634
+ attempts: summary.attempts,
7635
+ nextRetryAt: summary.nextRetryAt,
7636
+ updatedAt: summary.updatedAt
7637
+ } : null,
7597
7638
  status,
7598
7639
  eventExtraction: extraction ? {
7599
7640
  status: extraction.status,
@@ -7614,6 +7655,7 @@ async function memories(runtime, url) {
7614
7655
  const latestSealedTurn = scopedBlocks.reduce((latest, block) => Math.max(latest, block.turnRange[1]), 0);
7615
7656
  const openMessages = activeThreadId ? recovered.openMessages.filter((message) => message.threadId === activeThreadId).map(({ message }) => message) : [];
7616
7657
  const openTurns = openMessages.filter(({ role }) => role === "user").length;
7658
+ const openDshTurns = activeThreadId ? openMessages.filter(({ role }) => role === "user").map((message) => recovered.receiptTurns.get(receiptTurnKey(activeThreadId, message.createdAt))) : [];
7617
7659
  return {
7618
7660
  namespace,
7619
7661
  kind,
@@ -7622,10 +7664,13 @@ async function memories(runtime, url) {
7622
7664
  limit,
7623
7665
  items: filtered2.slice(offset, offset + limit),
7624
7666
  openBlock: {
7625
- turnRange: openTurns > 0 ? [latestSealedTurn + 1, latestSealedTurn + openTurns] : null,
7667
+ turnRange: openTurns > 0 ? openDshTurns.length > 0 && openDshTurns.every((turn) => turn !== void 0) ? [Math.min(...openDshTurns), Math.max(...openDshTurns)] : [latestSealedTurn + 1, latestSealedTurn + openTurns] : null,
7626
7668
  messages: openMessages.length,
7669
+ turns: openTurns,
7670
+ capacity: snapshot.blockTurnSize,
7627
7671
  status: "open"
7628
7672
  },
7673
+ blockTurnSize: snapshot.blockTurnSize,
7629
7674
  conversations,
7630
7675
  activeThreadId
7631
7676
  };