stratagate-dsh 0.2.68 → 0.2.70

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/plugin.js CHANGED
@@ -1316,6 +1316,7 @@ function normalizeRetrievalAssessment(input, batchEvidenceRefs) {
1316
1316
  // packages/core/src/storage.ts
1317
1317
  var STRATAGATE_STORAGE_SCHEMA_VERSION = 10;
1318
1318
  var KNOWLEDGE_GRAPH_PROJECTOR_VERSION = 1;
1319
+ var DERIVATION_MAX_ATTEMPTS = 3;
1319
1320
  var StorageConflictError = class extends Error {
1320
1321
  constructor(namespace, expectedRevision, actualRevision) {
1321
1322
  super(`Storage revision conflict for ${namespace}: expected ${expectedRevision}, found ${actualRevision ?? "missing"}`);
@@ -1467,6 +1468,9 @@ function normalizeSnapshot(value) {
1467
1468
  if (!Array.isArray(snapshot[key])) throw new TypeError(`Invalid StrataGate snapshot: ${key} must be an array`);
1468
1469
  }
1469
1470
  if (!Array.isArray(snapshot.successfulModelResponses)) snapshot.successfulModelResponses = [];
1471
+ for (const job of snapshot.graphProjectionJobs) {
1472
+ if (job.nextRetryAt === void 0) job.nextRetryAt = null;
1473
+ }
1470
1474
  for (const event of snapshot.events) {
1471
1475
  event.temporal = { ...event.temporal, eventType: normalizeStandardEventType(event.temporal.eventType) };
1472
1476
  }
@@ -2192,8 +2196,7 @@ var SqliteStorage = class {
2192
2196
  externalMemoryImportJobs,
2193
2197
  successfulModelResponses
2194
2198
  };
2195
- assertValidSnapshot(snapshot);
2196
- return { snapshot: cloneSnapshot(snapshot), revision: space.revision };
2199
+ return { snapshot: cloneSnapshot(normalizeSnapshot(snapshot)), revision: space.revision };
2197
2200
  }
2198
2201
  async save(namespace, snapshot, expectedRevision) {
2199
2202
  this.assertOpen();
@@ -2734,7 +2737,6 @@ var EXTERNAL_MEMORY_AUTO_APPLY_CONFIDENCE = 0.85;
2734
2737
  function externalMemoryFingerprint(value) {
2735
2738
  return `${normalizeSearchText(value.title)}\0${normalizeSearchText(value.summary)}`;
2736
2739
  }
2737
- var DERIVATION_MAX_ATTEMPTS = 3;
2738
2740
  var DERIVATION_BACKOFF_MS = 1e3;
2739
2741
  var StrataGate = class _StrataGate {
2740
2742
  blockTurnSizeValue;
@@ -2919,6 +2921,7 @@ var StrataGate = class _StrataGate {
2919
2921
  ...job,
2920
2922
  status: "failed",
2921
2923
  lastError: "Graph projection was interrupted before completion.",
2924
+ nextRetryAt: memory.retryAt(job.attempts),
2922
2925
  updatedAt: now
2923
2926
  });
2924
2927
  }
@@ -3077,6 +3080,7 @@ var StrataGate = class _StrataGate {
3077
3080
  job.status = "pending";
3078
3081
  job.attempts = 0;
3079
3082
  job.lastError = null;
3083
+ job.nextRetryAt = null;
3080
3084
  job.updatedAt = toUtc8Iso(this.now());
3081
3085
  });
3082
3086
  const batch = await this.claimGraphProjection(jobId);
@@ -3675,7 +3679,7 @@ var StrataGate = class _StrataGate {
3675
3679
  }
3676
3680
  async claimNextElementProjection() {
3677
3681
  return this.commitMutation(() => {
3678
- const job = [...this.elementProjectionJobs.values()].find((candidate) => candidate.status === "pending" || candidate.status === "failed");
3682
+ const job = [...this.elementProjectionJobs.values()].filter((candidate) => candidate.attempts < DERIVATION_MAX_ATTEMPTS && (candidate.status === "pending" || candidate.status === "failed")).sort((left, right) => Number(left.status !== "pending") - Number(right.status !== "pending") || left.createdAt.localeCompare(right.createdAt))[0];
3679
3683
  if (!job) return null;
3680
3684
  const events = job.sourceEventIds.flatMap((id) => this.events.find((event) => event.id === id) ?? []);
3681
3685
  if (events.length === 0) {
@@ -3729,7 +3733,8 @@ var StrataGate = class _StrataGate {
3729
3733
  }
3730
3734
  async claimGraphProjection(jobId) {
3731
3735
  return this.commitMutation(() => {
3732
- const job = [...this.graphProjectionJobs.values()].filter((candidate) => (jobId === void 0 || candidate.id === jobId) && (candidate.status === "pending" || candidate.status === "failed")).sort((left, right) => right.priority - left.priority || left.createdAt.localeCompare(right.createdAt))[0];
3736
+ const now = this.now().getTime();
3737
+ const job = [...this.graphProjectionJobs.values()].filter((candidate) => (jobId === void 0 || candidate.id === jobId) && candidate.attempts < DERIVATION_MAX_ATTEMPTS && (candidate.status === "pending" || candidate.status === "failed" && candidate.nextRetryAt !== null && Date.parse(candidate.nextRetryAt) <= now)).sort((left, right) => Number(left.status !== "pending") - Number(right.status !== "pending") || right.priority - left.priority || left.createdAt.localeCompare(right.createdAt))[0];
3733
3738
  if (!job) return null;
3734
3739
  const events = job.sourceEventIds.flatMap((id) => this.events.find((event) => event.id === id) ?? []);
3735
3740
  if (events.length === 0) throw new Error(`Graph projection ${job.id} has no available source events`);
@@ -3744,14 +3749,14 @@ var StrataGate = class _StrataGate {
3744
3749
  (event.temporal.participants ?? []).join(" ")
3745
3750
  ].join(" ")).join(" "));
3746
3751
  const relevantNodes = this.graphNodes.filter((node) => [node.name, ...node.aliases].some((name2) => eventText.includes(normalizeSearchText(name2)))).concat([...this.graphNodes].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)).slice(0, 24));
3747
- const existingNodes = [...new Map(relevantNodes.map((node) => [node.id, node])).values()].slice(0, 80);
3752
+ const existingNodes = [...new Map(relevantNodes.map((node) => [node.id, node])).values()].slice(0, 32);
3748
3753
  const nodeIds = new Set(existingNodes.map(({ id }) => id));
3749
3754
  return {
3750
3755
  jobId: job.id,
3751
3756
  projectorVersion: job.projectorVersion,
3752
3757
  events: structuredClone(events),
3753
3758
  existingNodes: structuredClone(existingNodes),
3754
- existingEdges: structuredClone(this.graphEdges.filter(({ fromNodeId, toNodeId }) => nodeIds.has(fromNodeId) && nodeIds.has(toNodeId)).slice(-120))
3759
+ existingEdges: structuredClone(this.graphEdges.filter(({ fromNodeId, toNodeId }) => nodeIds.has(fromNodeId) && nodeIds.has(toNodeId)).slice(-60))
3755
3760
  };
3756
3761
  });
3757
3762
  }
@@ -3777,6 +3782,7 @@ var StrataGate = class _StrataGate {
3777
3782
  job.edgeIds = touched.edgeIds;
3778
3783
  job.reason = typeof result.reason === "string" ? result.reason.trim().replace(/\s+/g, " ").slice(0, 500) || null : null;
3779
3784
  job.lastError = null;
3785
+ job.nextRetryAt = null;
3780
3786
  job.updatedAt = toUtc8Iso(this.now());
3781
3787
  return touched;
3782
3788
  });
@@ -3787,6 +3793,7 @@ var StrataGate = class _StrataGate {
3787
3793
  if (job.status === "completed") return;
3788
3794
  job.status = "failed";
3789
3795
  job.lastError = errorMessage(error);
3796
+ job.nextRetryAt = this.retryAt(job.attempts);
3790
3797
  job.updatedAt = toUtc8Iso(this.now());
3791
3798
  });
3792
3799
  }
@@ -4169,6 +4176,7 @@ var StrataGate = class _StrataGate {
4169
4176
  edgeIds: [],
4170
4177
  reason: null,
4171
4178
  lastError: null,
4179
+ nextRetryAt: null,
4172
4180
  createdAt: now,
4173
4181
  updatedAt: now
4174
4182
  };
@@ -4991,6 +4999,48 @@ function renderBlocksForDiagnostics(blocks, finish) {
4991
4999
  const rendered = blocks.map(renderBlockForDiagnostics).join("\n\n");
4992
5000
  return rendered || `[no model blocks; finish=${finish}]`;
4993
5001
  }
5002
+ function compactGraphProjectionContext(context) {
5003
+ const compactValue = (value) => Array.isArray(value) ? value.slice(0, 12).map((entry) => entry.slice(0, 160)) : value.slice(0, 400);
5004
+ return {
5005
+ jobId: context.jobId,
5006
+ projectorVersion: context.projectorVersion,
5007
+ events: context.events.map((event) => ({
5008
+ id: event.id,
5009
+ title: event.title,
5010
+ summary: event.summary,
5011
+ narrative: event.narrative,
5012
+ tags: event.tags,
5013
+ quotes: event.quotes,
5014
+ temporal: event.temporal,
5015
+ scope: event.scope,
5016
+ criticality: event.criticality,
5017
+ status: event.status
5018
+ })),
5019
+ existingNodes: context.existingNodes.slice(0, 32).map((node) => ({
5020
+ id: node.id,
5021
+ name: node.name,
5022
+ type: node.type,
5023
+ aliases: node.aliases.slice(0, 12),
5024
+ tags: node.tags?.slice(0, 12),
5025
+ currentState: node.currentState.slice(0, 600),
5026
+ facts: node.facts.filter(({ status }) => status === "active" || status === "disputed").slice(-12).map((fact) => ({
5027
+ key: fact.key,
5028
+ value: compactValue(fact.value),
5029
+ status: fact.status,
5030
+ sourceEventIds: fact.sourceEventIds.slice(-16)
5031
+ })),
5032
+ status: node.status,
5033
+ sourceEventIds: node.sourceEventIds.slice(-16)
5034
+ })),
5035
+ existingEdges: context.existingEdges.slice(-60).map((edge) => ({
5036
+ fromNodeId: edge.fromNodeId,
5037
+ toNodeId: edge.toNodeId,
5038
+ relation: edge.relation,
5039
+ status: edge.status,
5040
+ sourceEventIds: edge.sourceEventIds.slice(-16)
5041
+ }))
5042
+ };
5043
+ }
4994
5044
  var DshModelBridge = class {
4995
5045
  constructor(ctx, config) {
4996
5046
  this.ctx = ctx;
@@ -5104,8 +5154,8 @@ var DshModelBridge = class {
5104
5154
  const eventIds = new Set(context.events.map((event) => event.id));
5105
5155
  const raw = object(await this.callStructured(
5106
5156
  "graphProjector",
5107
- `Project the supplied Events into the current Knowledge Graph, then call ${STRUCTURED_TOOLS.graphProjector.name} exactly once. Events are the sole source of truth; never use legacy Element data. Return stable entity nodes for people, projects, organizations, tools, and places. Use aliases to merge spelling/case/separator variants. Give every returned node 1-6 concise semantic role tags such as benchmark, evaluation, memory-plugin, parser, or development-tool; tags describe the node's specific role and never replace its person/project/organization/tool/place type. Reuse stable tag wording when possible. Put attributes in node facts and every relationship in a directed edge using fromRef/toRef\u2014never encode a relationship as a fact string. Prefer concise canonical Chinese relation labels such as \u4F7F\u7528\u3001\u5C5E\u4E8E\u3001\u521B\u5EFA\u3001\u53C2\u4E0E\u3001\u8D21\u732E\u3001\u4F9D\u8D56\u3001\u4F4D\u4E8E\u3001\u76F8\u5173. Every node, fact, and edge must cite only supplied Event ids. Do not return text.`,
5108
- context
5157
+ `Project the supplied Events into the current Knowledge Graph, then call ${STRUCTURED_TOOLS.graphProjector.name} exactly once. Events are the sole source of truth; never use legacy Element data. Return only nodes and edges touched by the supplied Events; never echo unchanged historical graph records. Return at most 24 nodes and 32 edges. Use stable entity nodes for people, projects, organizations, tools, and places. Use aliases to merge spelling/case/separator variants. Give every returned node 1-6 concise semantic role tags such as benchmark, evaluation, memory-plugin, parser, or development-tool; tags describe the node's specific role and never replace its person/project/organization/tool/place type. Reuse stable tag wording when possible. Put attributes in node facts and every relationship in a directed edge using fromRef/toRef\u2014never encode a relationship as a fact string. Prefer concise canonical Chinese relation labels such as \u4F7F\u7528\u3001\u5C5E\u4E8E\u3001\u521B\u5EFA\u3001\u53C2\u4E0E\u3001\u8D21\u732E\u3001\u4F9D\u8D56\u3001\u4F4D\u4E8E\u3001\u76F8\u5173. Every node, fact, and edge must cite only supplied Event ids. Do not return text.`,
5158
+ compactGraphProjectionContext(context)
5109
5159
  ));
5110
5160
  const nodes = (Array.isArray(raw.nodes) ? raw.nodes : []).flatMap((candidate) => {
5111
5161
  const item = object(candidate);
@@ -5134,7 +5184,7 @@ var DshModelBridge = class {
5134
5184
  ...typeof item.confidence === "number" ? { confidence: item.confidence } : {},
5135
5185
  sourceEventIds
5136
5186
  }];
5137
- });
5187
+ }).slice(0, 24);
5138
5188
  const refs = new Set(nodes.map(({ ref }) => ref));
5139
5189
  const edges = (Array.isArray(raw.edges) ? raw.edges : []).flatMap((candidate) => {
5140
5190
  const item = object(candidate);
@@ -5153,7 +5203,7 @@ var DshModelBridge = class {
5153
5203
  ...typeof item.confidence === "number" ? { confidence: item.confidence } : {},
5154
5204
  sourceEventIds
5155
5205
  }];
5156
- });
5206
+ }).slice(0, 32);
5157
5207
  return { reason: text2(raw.reason, "Projected Event evidence into the Knowledge Graph."), nodes, edges };
5158
5208
  };
5159
5209
  externalMemoryDecider = async (context) => {
@@ -5197,7 +5247,9 @@ var DshModelBridge = class {
5197
5247
  let useOff = await this.shouldUseOff(baseRoute);
5198
5248
  let lastError;
5199
5249
  let lastResponse = "";
5250
+ let attemptsUsed = 0;
5200
5251
  for (let attempt = 1; attempt <= JSON_RESPONSE_ATTEMPTS; attempt += 1) {
5252
+ attemptsUsed = attempt;
5201
5253
  const message = createUserMessage({
5202
5254
  content: [{ type: "text", text: JSON.stringify(payload) }],
5203
5255
  source: { kind: "plugin", plugin: "stratagate-memory" }
@@ -5306,13 +5358,14 @@ ${JSON_RETRY_INSTRUCTION}`,
5306
5358
  `StrataGate ${STRUCTURED_TOOLS[kind].name} call was truncated before valid arguments`,
5307
5359
  { cause: error, response: responseForError }
5308
5360
  ) : error;
5361
+ if (kind === "graphProjector" && finish.kind === "max-tokens") break;
5309
5362
  if (attempt < JSON_RESPONSE_ATTEMPTS) {
5310
5363
  this.ctx.logger.warn(`stratagate-memory model returned an invalid structured tool call; retrying (${attempt}/${JSON_RESPONSE_ATTEMPTS})`);
5311
5364
  }
5312
5365
  }
5313
5366
  }
5314
5367
  throw new ModelJsonResponseError(
5315
- `StrataGate model did not produce a valid ${STRUCTURED_TOOLS[kind].name} call after ${JSON_RESPONSE_ATTEMPTS} attempts`,
5368
+ `StrataGate model did not produce a valid ${STRUCTURED_TOOLS[kind].name} call after ${attemptsUsed} attempt${attemptsUsed === 1 ? "" : "s"}`,
5316
5369
  { cause: lastError, response: lastResponse }
5317
5370
  );
5318
5371
  }
@@ -5715,6 +5768,9 @@ var DRAIN_BASE_BACKOFF_MS = 2e3;
5715
5768
  var DRAIN_MAX_BACKOFF_MS = 6e4;
5716
5769
  var BACKGROUND_WORKER_INITIAL_DELAY_MS = 250;
5717
5770
  var BACKGROUND_WORKER_INTERVAL_MS = 3e3;
5771
+ function graphProjectionCanRun(job, now = Date.now()) {
5772
+ return job.attempts < DERIVATION_MAX_ATTEMPTS && (job.status === "pending" || job.status === "failed" && job.nextRetryAt != null && Date.parse(job.nextRetryAt) <= now);
5773
+ }
5718
5774
  var AUTO_EVENT_LIMIT = 4;
5719
5775
  var AUTO_ELEMENT_LIMIT = 4;
5720
5776
  var AUTO_MEMORY_TOKEN_BUDGET = 900;
@@ -5849,7 +5905,7 @@ var StrataGateRuntime = class {
5849
5905
  const runnable = [
5850
5906
  ...memory.listSummaryJobs(),
5851
5907
  ...memory.listExtractionJobs()
5852
- ].some((job) => job.status === "pending" || job.status === "failed" && job.nextRetryAt !== null && Date.parse(job.nextRetryAt) <= Date.now()) || memory.listGraphProjectionJobs().some(({ status }) => status === "pending");
5908
+ ].some((job) => job.status === "pending" || job.status === "failed" && job.nextRetryAt !== null && Date.parse(job.nextRetryAt) <= Date.now()) || memory.listGraphProjectionJobs().some((job) => graphProjectionCanRun(job));
5853
5909
  if (!runnable) return;
5854
5910
  const hasActiveSessionWork = [
5855
5911
  ...this.derivationTimers.keys(),
@@ -6217,6 +6273,11 @@ var StrataGateRuntime = class {
6217
6273
  retrievedMemories,
6218
6274
  incremented: eventIds.size + elementIds.size,
6219
6275
  evidenceRefs: selectedRefs,
6276
+ ...assessment === void 0 ? {} : {
6277
+ verdict: assessment.verdict,
6278
+ missing: assessment.missing,
6279
+ nextStrategy: assessment.nextStrategy
6280
+ },
6220
6281
  duplicateEvidenceRefs,
6221
6282
  eventIds: [...eventIds],
6222
6283
  elementIds: [...elementIds],
@@ -7122,7 +7183,7 @@ var StrataGateRuntime = class {
7122
7183
  const namespace = this.namespaceFor(session);
7123
7184
  if (this.closed || this.migrationTimers.has(namespace)) return;
7124
7185
  if (typeof memory.listGraphProjectionJobs !== "function") return;
7125
- const pending = memory.listGraphProjectionJobs().some(({ status }) => status === "pending" || status === "failed");
7186
+ const pending = memory.listGraphProjectionJobs().some((job) => graphProjectionCanRun(job));
7126
7187
  if (!pending) return;
7127
7188
  const timer = setTimeout(() => {
7128
7189
  this.migrationTimers.delete(namespace);
@@ -7828,6 +7889,10 @@ function currentPluginVersion() {
7828
7889
  return "unknown";
7829
7890
  }
7830
7891
  var STRATAGATE_DSH_VERSION = currentPluginVersion();
7892
+ function graphProjectionIsProcessing(job) {
7893
+ if (job.status === "running") return true;
7894
+ return job.attempts < DERIVATION_MAX_ATTEMPTS && (job.status === "pending" || job.status === "failed" && job.nextRetryAt !== null);
7895
+ }
7831
7896
  function installedPackageVersion(names) {
7832
7897
  for (const name2 of names) {
7833
7898
  try {
@@ -7908,7 +7973,81 @@ Tags: ${block.l0Tags.join(", ") || "none"}` },
7908
7973
  { level: 5, content: formatRawTranscript(block.l5Raw) }
7909
7974
  ]);
7910
7975
  }
7911
- function eventSummary(event) {
7976
+ function sampledEventWeight(event, turn, lastAdoptedTurn, mentionCount) {
7977
+ return memoryWeightAt({
7978
+ status: event.status,
7979
+ weight: { ...event.weight, lastAdoptedTurn, mentionCount }
7980
+ }, turn);
7981
+ }
7982
+ function appendWeightSegment(points, event, fromTurn, toTurn, mentionCount) {
7983
+ if (toTurn < fromTurn) return;
7984
+ if (toTurn === fromTurn) return;
7985
+ const span = toTurn - fromTurn;
7986
+ const step = Math.max(1, Math.ceil(span / 32));
7987
+ for (let turn = fromTurn; turn < toTurn; turn += step) {
7988
+ points.push({ turn, weight: sampledEventWeight(event, turn, fromTurn, mentionCount), kind: "sample" });
7989
+ }
7990
+ points.push({ turn: toTurn, weight: sampledEventWeight(event, toTurn, fromTurn, mentionCount), kind: "sample" });
7991
+ }
7992
+ function eventWeightTrajectory(snapshot, event) {
7993
+ const currentTurn = snapshot.currentTurn;
7994
+ const effectiveAdoptions = Math.max(0, event.weight.mentionCount - 1);
7995
+ const adoptionReceipts = snapshot.usageReceipts.filter(({ eventIds }) => eventIds.includes(event.id));
7996
+ const adoptionTurns = adoptionReceipts.map(({ audit: audit2 }) => audit2?.turn).filter((turn) => Number.isSafeInteger(turn) && turn >= 0).sort((left, right) => left - right);
7997
+ const historyComplete = adoptionReceipts.length === effectiveAdoptions && adoptionTurns.length === adoptionReceipts.length && (effectiveAdoptions === 0 || adoptionTurns.at(-1) === event.weight.lastAdoptedTurn);
7998
+ const canInterpolate = event.status !== "forgotten" && event.status !== "archived" && event.weight.forcedCap === null && !event.weight.pinned;
7999
+ const points = [];
8000
+ if (canInterpolate && effectiveAdoptions === 0) {
8001
+ appendWeightSegment(points, event, event.weight.lastAdoptedTurn, currentTurn, 1);
8002
+ if (points.length > 0) {
8003
+ const first = points[0];
8004
+ points[0] = { turn: first.turn, weight: first.weight, kind: "creation", label: "\u521B\u5EFA" };
8005
+ }
8006
+ } else if (canInterpolate && historyComplete && adoptionTurns.length > 0) {
8007
+ let anchorTurn = adoptionTurns[0];
8008
+ let mentionCount = 2;
8009
+ points.push({ turn: anchorTurn, weight: 1, kind: "adoption", label: "\u91C7\u7528" });
8010
+ for (const [index, turn] of adoptionTurns.slice(1).entries()) {
8011
+ appendWeightSegment(points, event, anchorTurn, turn, mentionCount);
8012
+ points.push({ turn, weight: 1, kind: "adoption", label: index === adoptionTurns.length - 2 ? "\u518D\u6B21\u91C7\u7528" : "\u91C7\u7528" });
8013
+ anchorTurn = turn;
8014
+ mentionCount += 1;
8015
+ }
8016
+ appendWeightSegment(points, event, anchorTurn, currentTurn, mentionCount);
8017
+ } else if (canInterpolate) {
8018
+ appendWeightSegment(points, event, event.weight.lastAdoptedTurn, currentTurn, event.weight.mentionCount);
8019
+ if (effectiveAdoptions > 0 && points.length > 0) {
8020
+ const first = points[0];
8021
+ points[0] = { turn: first.turn, weight: first.weight, kind: "adoption", label: "\u6700\u8FD1\u91C7\u7528" };
8022
+ }
8023
+ }
8024
+ const currentWeight = memoryWeightAt(event, currentTurn);
8025
+ if (points.length === 0 || points.at(-1)?.turn !== currentTurn) {
8026
+ points.push({ turn: currentTurn, weight: currentWeight, kind: "current", label: "\u5F53\u524D" });
8027
+ } else if (points.at(-1)?.kind === "creation" || points.at(-1)?.kind === "adoption") {
8028
+ points[points.length - 1] = {
8029
+ ...points[points.length - 1],
8030
+ weight: currentWeight,
8031
+ label: `${points[points.length - 1].label} \xB7 \u5F53\u524D`
8032
+ };
8033
+ } else {
8034
+ points[points.length - 1] = { ...points[points.length - 1], weight: currentWeight, kind: "current", label: "\u5F53\u524D" };
8035
+ }
8036
+ return {
8037
+ scale: "conversation_turn",
8038
+ currentTurn,
8039
+ currentWeight,
8040
+ effectiveAdoptions,
8041
+ latestAdoptionTurn: effectiveAdoptions > 0 ? event.weight.lastAdoptedTurn : null,
8042
+ turnsSinceLatestAdoption: effectiveAdoptions > 0 ? Math.max(0, currentTurn - event.weight.lastAdoptedTurn) : null,
8043
+ lastRetrievedAt: event.weight.lastRetrievedAt,
8044
+ recordedAdoptionTurns: adoptionTurns,
8045
+ historyComplete,
8046
+ points,
8047
+ note: !canInterpolate ? "\u56FA\u5B9A\u3001\u5C01\u5B58\u6216\u72B6\u6001\u4E0A\u9650\u7684\u53D8\u66F4\u8F6E\u6B21\u6CA1\u6709\u5386\u53F2\u8BB0\u5F55\uFF0C\u56E0\u6B64\u4EC5\u663E\u793A\u5F53\u524D\u771F\u5B9E\u6743\u91CD\u3002" : effectiveAdoptions > 0 && !historyComplete ? "\u90E8\u5206\u65E9\u671F\u91C7\u7528\u8BB0\u5F55\u7F3A\u5C11\u8F6E\u6B21\uFF1B\u66F2\u7EBF\u4EC5\u4ECE\u6700\u8FD1\u4E00\u6B21\u53EF\u786E\u8BA4\u7684\u5F3A\u5316\u5F00\u59CB\u3002" : effectiveAdoptions > 0 ? "\u91C7\u7528\u8F6E\u6B21\u6765\u81EA\u4F7F\u7528\u56DE\u6267\uFF1B\u521B\u5EFA\u8F6E\u6B21\u672A\u5355\u72EC\u4FDD\u5B58\uFF0C\u56E0\u6B64\u4E0D\u63A8\u6D4B\u521B\u5EFA\u8282\u70B9\u3002" : "\u5C1A\u672A\u53D1\u751F\u6709\u6548\u91C7\u7528\uFF1B\u521B\u5EFA\u951A\u70B9\u6765\u81EA Event \u5F53\u524D\u6743\u91CD\u72B6\u6001\u3002"
8048
+ };
8049
+ }
8050
+ function eventSummary(event, snapshot) {
7912
8051
  return {
7913
8052
  id: event.id,
7914
8053
  title: event.title,
@@ -7924,6 +8063,7 @@ function eventSummary(event) {
7924
8063
  status: event.status,
7925
8064
  supersededBy: event.supersededBy,
7926
8065
  weight: event.weight,
8066
+ ...snapshot ? { weightTrajectory: eventWeightTrajectory(snapshot, event) } : {},
7927
8067
  createdAt: event.createdAt,
7928
8068
  updatedAt: event.updatedAt
7929
8069
  };
@@ -8020,7 +8160,7 @@ async function overview(runtime, cachedEntries) {
8020
8160
  kind: "graph-projection",
8021
8161
  status: job.status,
8022
8162
  attempts: job.attempts,
8023
- nextRetryAt: null,
8163
+ nextRetryAt: job.nextRetryAt,
8024
8164
  lastError: job.lastError?.slice(0, 500) ?? null,
8025
8165
  lastErrorFull: job.lastError,
8026
8166
  updatedAt: job.updatedAt,
@@ -8032,7 +8172,7 @@ async function overview(runtime, cachedEntries) {
8032
8172
  };
8033
8173
  };
8034
8174
  const failedJobs = snapshot.summaryJobs.filter(({ status }) => status === "failed").length + snapshot.extractionJobs.filter(({ status }) => status === "failed").length + snapshot.graphProjectionJobs.filter(({ status }) => status === "failed").length;
8035
- const processingJobs = snapshot.summaryJobs.filter(({ status, nextRetryAt }) => status === "pending" || status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.extractionJobs.filter(({ status, nextRetryAt }) => status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.graphProjectionJobs.filter(({ status }) => status === "pending" || status === "running").length;
8175
+ const processingJobs = snapshot.summaryJobs.filter(({ status, nextRetryAt }) => status === "pending" || status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.extractionJobs.filter(({ status, nextRetryAt }) => status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.graphProjectionJobs.filter(graphProjectionIsProcessing).length;
8036
8176
  const failedJobDetails = [
8037
8177
  ...snapshot.summaryJobs.filter(({ status }) => status === "failed").map((job) => describeBlockJob("block-summary", job)),
8038
8178
  ...snapshot.extractionJobs.filter(({ status }) => status === "failed").map((job) => describeBlockJob("event-extraction", job)),
@@ -8041,7 +8181,7 @@ async function overview(runtime, cachedEntries) {
8041
8181
  const processingJobDetails = [
8042
8182
  ...snapshot.summaryJobs.filter(({ status, nextRetryAt }) => status === "pending" || status === "running" || status === "failed" && nextRetryAt !== null).map((job) => describeBlockJob("block-summary", job)),
8043
8183
  ...snapshot.extractionJobs.filter(({ status, nextRetryAt }) => status === "running" || status === "failed" && nextRetryAt !== null).map((job) => describeBlockJob("event-extraction", job)),
8044
- ...snapshot.graphProjectionJobs.filter(({ status }) => status === "pending" || status === "running").map(describeGraphJob)
8184
+ ...snapshot.graphProjectionJobs.filter(graphProjectionIsProcessing).map(describeGraphJob)
8045
8185
  ];
8046
8186
  const timestamps = [
8047
8187
  ...snapshot.blocks.map(({ createdAt }) => createdAt),
@@ -8373,7 +8513,7 @@ async function memories(runtime, url) {
8373
8513
  const time = (event) => event.temporal.happenedStart ?? event.temporal.happenedEnd ?? event.temporal.mentionedAt ?? event.createdAt;
8374
8514
  return time(right).localeCompare(time(left));
8375
8515
  }).map((event) => ({
8376
- ...eventSummary(event),
8516
+ ...eventSummary(event, snapshot),
8377
8517
  relatedNodes: snapshot.graphNodes.filter(({ id, sourceEventIds }) => sourceEventIds.includes(event.id) || (event.temporal.participantNodeIds ?? []).includes(id)).map(({ id, name: name2, type }) => ({ id, name: name2, type })),
8378
8518
  relatedElements: snapshot.elements.filter(({ sourceEventIds }) => sourceEventIds.includes(event.id)).map(({ id, name: name2 }) => ({ id, name: name2 }))
8379
8519
  }));
@@ -8385,7 +8525,7 @@ async function memories(runtime, url) {
8385
8525
  projectorVersion: KNOWLEDGE_GRAPH_PROJECTOR_VERSION,
8386
8526
  nodes: snapshot.graphNodes.map((node) => ({
8387
8527
  ...node,
8388
- supportingEvents: node.sourceEventIds.flatMap((id) => eventMap.get(id) ?? []).map(eventSummary)
8528
+ supportingEvents: node.sourceEventIds.flatMap((id) => eventMap.get(id) ?? []).map((event) => eventSummary(event))
8389
8529
  })),
8390
8530
  edges: snapshot.graphEdges,
8391
8531
  clusters: clusterKnowledgeGraph(snapshot.graphNodes, snapshot.graphEdges),
@@ -8474,7 +8614,7 @@ async function memories(runtime, url) {
8474
8614
  jobs: projections.length,
8475
8615
  lastError: failedProjection?.lastError ?? null
8476
8616
  } : null,
8477
- relatedEvents: relatedEvents.map(eventSummary),
8617
+ relatedEvents: relatedEvents.map((event) => eventSummary(event)),
8478
8618
  relatedNodes
8479
8619
  };
8480
8620
  });
@@ -8533,7 +8673,7 @@ async function sources(runtime, url) {
8533
8673
  node,
8534
8674
  nodes: snapshot.graphNodes.filter(({ id }) => relatedNodeIds.has(id)),
8535
8675
  edges,
8536
- events: events.map(eventSummary),
8676
+ events: events.map((event) => eventSummary(event)),
8537
8677
  messages: sourceMessages(snapshot, ids)
8538
8678
  };
8539
8679
  } else if (elementId) {
@@ -8553,7 +8693,7 @@ async function sources(runtime, url) {
8553
8693
  elements = snapshot.elements.filter(({ sourceEventIds }) => sourceEventIds.some((id) => eventIds.has(id)));
8554
8694
  return {
8555
8695
  namespace,
8556
- events: events.map(eventSummary),
8696
+ events: events.map((event) => eventSummary(event)),
8557
8697
  elements: elements.map(elementSummary),
8558
8698
  messages: sourceMessages(snapshot, ids),
8559
8699
  layers: displayBlock ? virtualBlockLayers(displayBlock) : blockLayers(block),
@@ -8564,7 +8704,7 @@ async function sources(runtime, url) {
8564
8704
  }
8565
8705
  return {
8566
8706
  namespace,
8567
- events: events.map(eventSummary),
8707
+ events: events.map((event) => eventSummary(event, eventId ? snapshot : void 0)),
8568
8708
  elements: elements.map(elementSummary),
8569
8709
  blocks: events.map((event) => snapshot.blocks.find(({ id }) => id === event.sourceBlockId)).filter((block) => Boolean(block)).map((block) => ({ id: block.id, title: block.l0Title, createdAt: block.createdAt })),
8570
8710
  messages: sourceMessages(snapshot, ids)
@@ -8624,7 +8764,7 @@ function receiptSources(snapshot, receipt) {
8624
8764
  const messageIds = new Set(supportingEvents.flatMap(({ sourceMessageIds }) => sourceMessageIds));
8625
8765
  return {
8626
8766
  ...receipt,
8627
- events: events.map(eventSummary),
8767
+ events: events.map((event) => eventSummary(event)),
8628
8768
  elements: elements.map(elementSummary),
8629
8769
  sourceMessages: sourceMessages(snapshot, messageIds)
8630
8770
  };