stratagate-dsh 0.2.90 → 0.2.92

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
@@ -1864,6 +1864,8 @@ function normalizeSnapshot(value) {
1864
1864
  }
1865
1865
  const sourceBlockMap = new Map(snapshot.blocks.map((block) => [block.id, block]));
1866
1866
  for (const event of [...snapshot.events, ...snapshot.agentEvents]) {
1867
+ delete event.narrative;
1868
+ delete event.confidence;
1867
1869
  event.temporal = { ...event.temporal, eventType: normalizeStandardEventType(event.temporal.eventType) };
1868
1870
  if (event.formedTurn === void 0) {
1869
1871
  const sourceBlock = event.sourceBlockId !== void 0 ? sourceBlockMap.get(event.sourceBlockId) : void 0;
@@ -2408,7 +2410,6 @@ function mapEventRows(rows, sourcesByEvent, table) {
2408
2410
  id: row.id,
2409
2411
  title: row.title,
2410
2412
  summary: row.summary,
2411
- narrative: row.narrative,
2412
2413
  tags: parseJson(row.tags_json, `${table}.tags_json`),
2413
2414
  quotes: parseJson(row.quotes_json, `${table}.quotes_json`),
2414
2415
  sourceMessageIds: sourcesByEvent.get(row.id) ?? [],
@@ -2420,7 +2421,6 @@ function mapEventRows(rows, sourcesByEvent, table) {
2420
2421
  })(),
2421
2422
  scope: row.scope,
2422
2423
  criticality: row.criticality,
2423
- confidence: row.confidence,
2424
2424
  status: row.status,
2425
2425
  supersededBy: row.superseded_by,
2426
2426
  weight: {
@@ -3043,7 +3043,7 @@ var SqliteStorage = class {
3043
3043
  eventPosition,
3044
3044
  event.title,
3045
3045
  event.summary,
3046
- event.narrative,
3046
+ event.summary,
3047
3047
  JSON.stringify(event.tags),
3048
3048
  JSON.stringify(event.quotes),
3049
3049
  event.sourceBlockId,
@@ -3051,7 +3051,7 @@ var SqliteStorage = class {
3051
3051
  JSON.stringify(event.temporal),
3052
3052
  event.scope,
3053
3053
  event.criticality,
3054
- event.confidence,
3054
+ 1,
3055
3055
  event.status,
3056
3056
  event.supersededBy,
3057
3057
  event.weight.mentionCount,
@@ -3087,7 +3087,7 @@ var SqliteStorage = class {
3087
3087
  eventPosition,
3088
3088
  event.title,
3089
3089
  event.summary,
3090
- event.narrative,
3090
+ event.summary,
3091
3091
  JSON.stringify(event.tags),
3092
3092
  JSON.stringify(event.quotes),
3093
3093
  event.sourceBlockId ?? null,
@@ -3095,7 +3095,7 @@ var SqliteStorage = class {
3095
3095
  JSON.stringify(event.temporal),
3096
3096
  event.scope,
3097
3097
  event.criticality,
3098
- event.confidence,
3098
+ 1,
3099
3099
  event.status,
3100
3100
  event.supersededBy,
3101
3101
  event.weight.mentionCount,
@@ -3685,6 +3685,19 @@ function agentEventCandidate(content, category, now, threadId) {
3685
3685
  };
3686
3686
  }
3687
3687
  var DERIVATION_BACKOFF_MS = 1e3;
3688
+ function restrictExtractionRelations(temporal, allowedIds) {
3689
+ const result = { ...temporal };
3690
+ if (typeof result.sameEventId !== "string" || !allowedIds.has(result.sameEventId)) {
3691
+ delete result.sameEventId;
3692
+ }
3693
+ for (const field of ["beforeEventIds", "afterEventIds", "supersedesEventIds", "conflictsWithEventIds", "relatedEventIds"]) {
3694
+ const values = temporal[field];
3695
+ const ids = Array.isArray(values) ? [...new Set(values.filter((id) => typeof id === "string" && allowedIds.has(id)))] : [];
3696
+ if (ids.length > 0) result[field] = ids;
3697
+ else delete result[field];
3698
+ }
3699
+ return result;
3700
+ }
3688
3701
  var StrataGate = class _StrataGate {
3689
3702
  blockTurnSizeValue;
3690
3703
  blockDecayLambdaValue;
@@ -4636,7 +4649,6 @@ var StrataGate = class _StrataGate {
4636
4649
  [event.summary, 3],
4637
4650
  [event.tags.join(" "), 2],
4638
4651
  [event.quotes.join(" "), 2],
4639
- [event.narrative, 1],
4640
4652
  [(event.temporal.participants ?? []).join(" "), 5],
4641
4653
  [event.temporal.eventType ?? "", 5],
4642
4654
  [event.temporal.originalText ?? "", 4],
@@ -5383,7 +5395,6 @@ var StrataGate = class _StrataGate {
5383
5395
  formedTurn: parts.formedTurn,
5384
5396
  title: input.title.trim(),
5385
5397
  summary: input.summary.trim(),
5386
- narrative: input.narrative?.trim() || input.summary.trim(),
5387
5398
  tags: [...new Set(input.tags ?? [])].slice(0, 12),
5388
5399
  quotes: [...new Set(input.quotes ?? [])].slice(0, 12),
5389
5400
  sourceMessageIds: parts.sourceMessageIds,
@@ -5394,7 +5405,6 @@ var StrataGate = class _StrataGate {
5394
5405
  },
5395
5406
  scope: input.scope ?? "user",
5396
5407
  criticality: parts.criticality,
5397
- confidence: Math.max(0, Math.min(1, input.confidence ?? 1)),
5398
5408
  status: "active",
5399
5409
  supersededBy: null,
5400
5410
  weight: {
@@ -5905,6 +5915,7 @@ var StrataGate = class _StrataGate {
5905
5915
  });
5906
5916
  });
5907
5917
  let result;
5918
+ let allowedTimelineEventIds = /* @__PURE__ */ new Set();
5908
5919
  try {
5909
5920
  const query = [target.l0Title, target.l1Summary, ...target.l2Keypoints ?? []].filter(Boolean).join(" ");
5910
5921
  const relevant = query ? (await this.searchEvents(query, { limit: 8, trackRetrieval: false })).map(({ event }) => event) : [];
@@ -5914,11 +5925,12 @@ var StrataGate = class _StrataGate {
5914
5925
  for (const event of recent) {
5915
5926
  if (!timelineEvents.has(event.id)) timelineEvents.set(event.id, event);
5916
5927
  }
5928
+ allowedTimelineEventIds = new Set(timelineEvents.keys());
5917
5929
  result = await this.extractor({
5918
5930
  previous: threadBlocks.slice(0, targetIndex).reverse().find((block) => block.l2Keypoints !== void 0) ?? null,
5919
5931
  target,
5920
5932
  next,
5921
- timeline: [...timelineEvents.values()].map((event) => ({ id: event.id, title: event.title, temporal: event.temporal }))
5933
+ timeline: [...timelineEvents.values()].map((event) => ({ id: event.id, title: event.title, temporal: structuredClone(event.temporal) }))
5922
5934
  });
5923
5935
  } catch (error) {
5924
5936
  await this.commitMutation(() => {
@@ -5950,7 +5962,15 @@ var StrataGate = class _StrataGate {
5950
5962
  throw new Error(reason);
5951
5963
  }
5952
5964
  return this.commitMutation(() => {
5953
- const extracted = result.shouldExtract ? result.events.map((event) => this.addEventInMemory({ ...event, sourceBlockId: target.id })) : [];
5965
+ const allowedIds = new Set([...allowedTimelineEventIds].filter((id) => {
5966
+ const event = this.findEvent(id);
5967
+ return event?.status === "active" || event?.status === "superseded";
5968
+ }));
5969
+ const extracted = result.shouldExtract ? result.events.map((event) => this.addEventInMemory({
5970
+ ...event,
5971
+ sourceBlockId: target.id,
5972
+ ...event.temporal ? { temporal: restrictExtractionRelations(event.temporal, allowedIds) } : {}
5973
+ })) : [];
5954
5974
  if (extracted.length > 0) {
5955
5975
  const ids = extracted.map(({ id }) => id);
5956
5976
  this.queueElementProjection(ids);
@@ -6526,22 +6546,20 @@ var EVENT_ITEM = {
6526
6546
  type: "object",
6527
6547
  additionalProperties: false,
6528
6548
  properties: {
6529
- title: { type: "string", required: true },
6530
- summary: { type: "string", required: true },
6531
- narrative: { type: "string" },
6532
- tags: STRING_ARRAY,
6533
- quotes: STRING_ARRAY,
6534
- sourceMessageIds: { ...STRING_ARRAY, required: true },
6535
- temporal: OPEN_OBJECT,
6536
- scope: { type: "string", enum: ["user", "project", "session"] },
6537
- criticality: { type: "string", enum: ["routine", "preference", "identity", "safety"] },
6538
- confidence: { type: "number" }
6549
+ title: { type: "string", description: "A short, specific, retrieval-friendly title stating the canonical subject and the single main event or state change. Prefer explicit names, versions, tools, projects, or decisions supported by the source. Avoid pronouns, vague wording, unsupported synonyms, and keyword stuffing.", required: true },
6550
+ summary: { type: "string", description: "A concise, self-contained statement of one event: identify the concrete subject, what happened or became true, and the important result or current status. Preserve exact names and distinctive source-supported terms useful for retrieval. Do not add unstated causes, conclusions, certainty, or relationships.", required: true },
6551
+ tags: { ...STRING_ARRAY, description: "A small set of distinctive retrieval labels that add useful search entry points not already obvious from the event type or participants. Use only source-supported canonical names, projects, tools, versions, technologies, concepts, aliases, or abbreviations. Avoid generic, speculative, weakly related, or redundant tags." },
6552
+ quotes: { ...STRING_ARRAY, description: "A few short verbatim excerpts that directly support the extracted event and whose exact wording has lasting evidential or retrieval value. Copy exactly from the source messages. Do not quote unrelated context, paraphrase, or select wording that changes the original meaning." },
6553
+ sourceMessageIds: { ...STRING_ARRAY, description: "The smallest set of exact message IDs from the target Block that directly supports every material claim in this event. Do not include merely related messages, and do not cite messages that support only background context.", required: true },
6554
+ temporal: { ...OPEN_OBJECT, description: "Structured temporal and event metadata, including when the event happened or was mentioned, its event type, participants, precision, and basis. Preserve uncertainty and do not invent missing times, participants, chronology, or relationships." },
6555
+ scope: { type: "string", enum: ["user", "project", "session"], description: "The memory scope of the event: user for durable user-level facts or preferences, project for project-specific facts and decisions, and session only for temporary context that should not generalize beyond the current session." },
6556
+ criticality: { type: "string", enum: ["routine", "preference", "identity", "safety"], description: "The event's persistence class: routine for ordinary facts and outcomes, preference for durable user preferences, identity for stable identity-related facts, and safety only for safety-critical information. Do not inflate criticality merely because an event seems important." }
6539
6557
  }
6540
6558
  };
6541
6559
  var EXTRACTOR_PARAMETERS = {
6542
- shouldExtract: { type: "boolean", required: true },
6543
- reason: { type: "string", required: true },
6544
- events: { type: "array", items: EVENT_ITEM, required: true }
6560
+ shouldExtract: { type: "boolean", description: "The Event Extractor's final judgment: true only when at least one durable Event is directly supported by target.messages. False when none qualifies, even if the Summarizer pre-screen was true; then return an empty events array.", required: true },
6561
+ reason: { type: "string", description: "Briefly explain the final decision to extract or not extract; do not use this field as Event content.", required: true },
6562
+ events: { type: "array", items: EVENT_ITEM, description: "Zero or more atomic, self-contained Event cards directly supported by target.messages. Separate independently changing, conflicting, or retrievable facts.", required: true }
6545
6563
  };
6546
6564
  var VALUE = {
6547
6565
  oneOf: [
@@ -6656,7 +6674,7 @@ var STRUCTURED_TOOLS = {
6656
6674
  },
6657
6675
  extractor: {
6658
6676
  name: "stratagate_extract_event_cards",
6659
- description: "Submit durable, evidence-backed event cards from the target block only.",
6677
+ description: "Submit the Event Extractor's final decision and zero or more atomic, self-contained, source-grounded long-term Event cards. Extract only from target.messages; return shouldExtract=false and events=[] when no durable target-supported Event qualifies.",
6660
6678
  parameters: EXTRACTOR_PARAMETERS
6661
6679
  },
6662
6680
  projector: {
@@ -6706,7 +6724,6 @@ function compactGraphProjectionContext(context) {
6706
6724
  id: event.id,
6707
6725
  title: event.title,
6708
6726
  summary: event.summary,
6709
- narrative: event.narrative,
6710
6727
  tags: event.tags,
6711
6728
  quotes: event.quotes,
6712
6729
  temporal: event.temporal,
@@ -6810,7 +6827,15 @@ var DshModelBridge = class {
6810
6827
  const validMessageIds = new Set(context.target.l5Raw.map((message) => message.id));
6811
6828
  const raw = object(await this.callStructured(
6812
6829
  "extractor",
6813
- `Extract only durable, evidence-backed events from target.messages, then call ${STRUCTURED_TOOLS.extractor.name} exactly once. target.messages is a provenance-preserving derivation view of the target block: message ids and conversational text are retained, while tool code and oversized tool payloads may be marked compacted. Use the retained tool names, evidence summaries, and excerpts without inventing omitted details. The target block is the only legal source of new facts, quotations, and sourceMessageIds. neighbors.previous and neighbors.next are context-only L2 summaries; never extract from them. Every sourceMessageIds entry must exactly match allowedSourceMessageIds. If a fact appears only in a neighbor, do not extract it in this call. Events must be understandable later without the original chat. Use project scope for repository decisions, user scope for stable preferences/identity, and session scope for temporary task state. temporal.eventType must use exactly one stable value: decision, release, task_completed, plan, change, cancellation, incident, meeting, collaboration, migration, or other. temporal.participants contains canonical entity names. Use ISO-8601 timestamps with the explicit +08:00 offset in temporal fields. Keep happened time separate from mentionedAt; when happened time is unknown omit it and set precision/basis to unknown. Do not turn an assistant statement that merely recalls older memory into a new event; require new human input or a new observable task/tool outcome from target.messages. Do not return the result as text.`,
6830
+ `You are the StrataGate Event Extractor. Make the final extraction decision independently of the Summarizer's high-recall pre-screen. Extract durable, evidence-backed events from target.messages, then call ${STRUCTURED_TOOLS.extractor.name} exactly once. If none qualifies, set shouldExtract=false and events=[]; give a brief reason, not an Event body.
6831
+
6832
+ Each Event is one atomic fact, decision, plan, outcome, or state change that can independently be retrieved, updated, superseded, or contradicted. If two facts can change or conflict separately, create separate Events; never combine them merely to reduce the Event count. Make title and summary self-contained: name the concrete subject rather than using it, this project, that tool, this issue, or the previous one. The title names the subject and one main change; the summary states the complete supported fact and current status; tags add distinct source-supported search entry points not already covered by title, summary, participants, or eventType. Keep real canonical names, aliases, abbreviations, versions, tools, technologies, projects, and distinctive concepts useful for later retrieval. Never invent keywords, unsupported synonyms, aliases, causes, relationships, or certainty, and never stuff keywords.
6833
+
6834
+ Preserve source certainty and attribution: distinguish a user statement or decision, an assistant proposal or hypothesis, a tool-observed result, a plan, a completed result, and an unresolved possibility. Do not turn a suggestion into a decision, a hypothesis into a cause, or a plan into a completed outcome. Every material claim, quotation, time, status, and relationship must match source evidence.
6835
+
6836
+ target.messages is a provenance-preserving derivation view of the target Block: message ids and conversational text are retained, while tool code and oversized tool payloads may be marked compacted. Use only retained tool names, evidence summaries, and excerpts; do not invent omitted details. Only target.messages may supply new facts, exact quotes, and sourceMessageIds. neighbors.previous and neighbors.next are context-only L2 summaries; timeline only helps identify historical relationships. Neither neighbors nor timeline nor an assistant recap of older memory can create a new Event. Require new human input or a new observable task/tool outcome from target.messages. Every sourceMessageIds entry must exactly match allowedSourceMessageIds and directly support the Event.
6837
+
6838
+ Use project scope for repository decisions, user scope for stable preferences/identity, and session scope for temporary task state. temporal.eventType must use exactly one stable value: decision, release, task_completed, plan, change, cancellation, incident, meeting, collaboration, migration, or other. temporal.participants contains canonical entity names. Use ISO-8601 timestamps with the explicit +08:00 offset in temporal fields. Keep happened time separate from mentionedAt; when happened time is unknown omit it and set precision/basis to unknown. Do not return the result as text.`,
6814
6839
  extractorPayload(context)
6815
6840
  ));
6816
6841
  const events = (Array.isArray(raw.events) ? raw.events : []).map((candidate) => {
@@ -6818,25 +6843,24 @@ var DshModelBridge = class {
6818
6843
  const sourceMessageIds = strings2(item.sourceMessageIds).filter((id) => validMessageIds.has(id));
6819
6844
  const scope = SCOPES.has(item.scope) ? item.scope : "project";
6820
6845
  const criticality = CRITICALITIES.has(item.criticality) ? item.criticality : "routine";
6821
- if (!text2(item.title) || !text2(item.summary) || sourceMessageIds.length === 0) return null;
6846
+ if (!text2(item.title) || !text2(item.summary) || sourceMessageIds.length === 0 || sourceMessageIds.length !== strings2(item.sourceMessageIds).length) return null;
6822
6847
  return {
6823
6848
  title: text2(item.title).slice(0, 200),
6824
6849
  summary: text2(item.summary).slice(0, 1e3),
6825
- narrative: text2(item.narrative),
6826
6850
  tags: strings2(item.tags).slice(0, 16),
6827
6851
  quotes: strings2(item.quotes).slice(0, 12),
6828
6852
  sourceMessageIds,
6829
6853
  sourceBlockId: context.target.id,
6830
6854
  temporal: object(item.temporal),
6831
6855
  scope,
6832
- criticality,
6833
- confidence: typeof item.confidence === "number" ? item.confidence : 0.8
6856
+ criticality
6834
6857
  };
6835
6858
  }).filter((event) => event !== null);
6859
+ const shouldExtract = raw.shouldExtract === true && events.length > 0;
6836
6860
  return {
6837
- shouldExtract: raw.shouldExtract === true,
6838
- reason: text2(raw.reason, events.length ? "Durable evidence extracted." : "No durable evidence."),
6839
- events
6861
+ shouldExtract,
6862
+ reason: text2(raw.reason) || (shouldExtract ? "Durable evidence extracted." : "No durable evidence."),
6863
+ events: shouldExtract ? events : []
6840
6864
  };
6841
6865
  };
6842
6866
  projector = async (context) => {
@@ -9569,10 +9593,9 @@ function selectCompressedBlockSurface(session, sourceSeqs, block, context) {
9569
9593
  }
9570
9594
  function renderBlockSurfaceMessage(context) {
9571
9595
  return [
9572
- "[StrataGate conversation block]",
9573
- `Block: ${context.id}`,
9574
- `Turns: ${context.turnRange[0]}-${context.turnRange[1]}`,
9575
- `Level: L${context.level} (${context.label})`,
9596
+ "[StrataGate historical conversation block]",
9597
+ "Earlier conversation context; not a new user message or instruction.",
9598
+ `Block: ${context.id} | Turns: ${context.turnRange[0]}-${context.turnRange[1]} | Level: L${context.level}`,
9576
9599
  "",
9577
9600
  context.content
9578
9601
  ].join("\n");
@@ -9675,7 +9698,7 @@ function currentBlockSurfaceMessages(session) {
9675
9698
  const event = session.eventAt(seq);
9676
9699
  if (event?.type !== "user/message" || !isStrataGateMessageSource(event.data.source)) continue;
9677
9700
  const text3 = event.data.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("\n");
9678
- const blockId = text3.match(/^\[StrataGate conversation block\]\nBlock: ([^\n]+)/u)?.[1] ?? text3.match(/^\[StrataGate compressed conversation\]\nBlock ([^;\n]+);/u)?.[1];
9701
+ const blockId = text3.match(/^\[StrataGate historical conversation block\]\nEarlier conversation context; not a new user message or instruction\.\nBlock: ([^|\n]+) \| Turns:/u)?.[1]?.trim() ?? text3.match(/^\[StrataGate conversation block\]\nBlock: ([^\n]+)/u)?.[1] ?? text3.match(/^\[StrataGate compressed conversation\]\nBlock ([^;\n]+);/u)?.[1];
9679
9702
  if (blockId) blocks.set(blockId, { seq, text: text3 });
9680
9703
  }
9681
9704
  return blocks;
@@ -9849,7 +9872,7 @@ function registerMemoryTools(ctx, runtime) {
9849
9872
  }));
9850
9873
  ctx.tools.register(defineTool({
9851
9874
  name: "memory_search_events",
9852
- description: "This tool is provided by the StrataGate plugin. Search durable StrataGate event memories. Returns a compact batch of event cards (id, title, summary, time, and evidence refs); call memory_expand_event for narrative/quotes/source messages. rankScore is BM25/RRF ordering only, never confidence or factual accuracy. Pass batchId to memory_assess before relying on evidence.",
9875
+ description: "This tool is provided by the StrataGate plugin. Search durable StrataGate event memories. Returns a compact batch of event cards (id, title, summary, time, and evidence refs); call memory_expand_event for the full summary, quotes, and source messages. rankScore is BM25/RRF ordering only, never confidence or factual accuracy. Pass batchId to memory_assess before relying on evidence.",
9853
9876
  parameters: {
9854
9877
  query: { type: "string", required: true, description: "What historical decision, event, preference, or outcome to find." },
9855
9878
  limit: { type: "integer", description: "Maximum results, 1-20." },
@@ -10364,14 +10387,12 @@ function eventSummary(event, snapshot) {
10364
10387
  formedTurn: event.formedTurn,
10365
10388
  title: event.title,
10366
10389
  summary: event.summary,
10367
- narrative: event.narrative,
10368
10390
  tags: event.tags,
10369
10391
  sourceBlockId: event.sourceBlockId,
10370
10392
  sourceMessageIds: event.sourceMessageIds,
10371
10393
  temporal: event.temporal,
10372
10394
  scope: event.scope,
10373
10395
  criticality: event.criticality,
10374
- confidence: event.confidence,
10375
10396
  status: event.status,
10376
10397
  supersededBy: event.supersededBy,
10377
10398
  weight: event.weight,
@@ -11679,6 +11700,19 @@ var STRATAGATE_SETTINGS_NAMESPACE = "stratagate-memory";
11679
11700
  var MEMORY_PROTOCOL = `[StrataGate memory protocol]
11680
11701
  StrataGate provides durable, evidence-gated memory through memory_* tools.
11681
11702
 
11703
+ StrataGate represents earlier conversation history as layered Blocks:
11704
+
11705
+ - L0: title and topical tags \u2014 the most compressed view.
11706
+ - L1: short self-contained summary.
11707
+ - L2: key facts, decisions, constraints, preferences, results, and open items.
11708
+ - L3: deterministically condensed conversation.
11709
+ - L4: readable near-verbatim conversation.
11710
+ - L5: complete source messages and tool records.
11711
+
11712
+ Higher levels contain more source detail.
11713
+ If the current level does not contain enough evidence for the task,
11714
+ do not infer omitted details; expand the Block or inspect raw memory.
11715
+
11682
11716
  - Search memory when the current task could depend on prior project decisions, user preferences, people, tools, historical outcomes, or unresolved work. Do not search for facts already established in the current conversation.
11683
11717
  - Start with memory_search_events for decisions and history, or memory_search_graph for the current state of a person/project/tool/place/organization.
11684
11718
  - Every retrieval creates an independent batch. Pass its batchId as batch_id to memory_assess before relying on it, especially when retrievals run in parallel. Adopt only evidenceRefs returned by that exact batch. Omitting batch_id selects the latest batch only for compatibility with strictly sequential calls.