stratagate-dsh 0.2.34 → 0.2.35
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 +6 -0
- package/README.md +7 -0
- package/dist/index.js +111 -10
- package/dist/index.js.map +1 -1
- package/docs/README.zh-CN.md +6 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.35 - 2026-08-27
|
|
4
|
+
|
|
5
|
+
- Return compact Event, Knowledge Graph, and raw-memory search cards while keeping full details in expand tools.
|
|
6
|
+
- Rename tool-facing ranking output to `rankScore` and document that it is not confidence or factual accuracy.
|
|
7
|
+
- Filter relation-only Knowledge Graph matches, report matched fields, and preserve distinct same-name entity types.
|
|
8
|
+
|
|
3
9
|
## 0.2.34 - 2026-08-27
|
|
4
10
|
|
|
5
11
|
- Add explicit `session` and `namespace` scopes to block and raw-memory retrieval.
|
package/README.md
CHANGED
|
@@ -110,6 +110,13 @@ blocks, and `open_tail_pending` means matching turns exist but have not sealed y
|
|
|
110
110
|
so a raw hit's `blockId` can be followed by `memory_get_blocks(scope=namespace)`
|
|
111
111
|
or `memory_expand_block` without an unexplained visibility mismatch.
|
|
112
112
|
|
|
113
|
+
Search responses use compact cards by default. Event cards keep `id`, `title`, `summary`, source time,
|
|
114
|
+
status/scope, `sourceBlockId`, `batchId`, and `evidenceRefs`; graph cards keep `id`, `name`, type,
|
|
115
|
+
aliases, current state, status, and explainable `matchedFields`/`matchReason`; raw cards keep the
|
|
116
|
+
message id, `blockId`, role, turn range, and a bounded excerpt. Narrative, quotes, source message lists,
|
|
117
|
+
full graph facts/edges, and nearby raw messages are available through the corresponding expand tools.
|
|
118
|
+
`rankScore` is a BM25/RRF ordering metric only—it is not a probability, confidence, or factual-accuracy score.
|
|
119
|
+
|
|
113
120
|
Legacy Element tool names remain available only for compatibility with existing installations.
|
|
114
121
|
|
|
115
122
|
The prompt protocol requires assessment before relying on retrieved evidence. Search does not strengthen a memory. Non-empty `memory_record_use` submissions accept only evidence adopted by a sufficient assessment of the selected batch and use the DSH tool call id as an idempotency receipt. `batch_id` may be omitted for compatibility in strictly sequential flows, where it selects the latest batch; parallel or interleaved retrievals must pass it explicitly. Assessment responses list rejected refs and their reasons.
|
package/dist/index.js
CHANGED
|
@@ -3479,6 +3479,16 @@ var StrataGate = class _StrataGate {
|
|
|
3479
3479
|
}
|
|
3480
3480
|
async searchGraphNodes(query, limit = 8) {
|
|
3481
3481
|
const candidates = this.graphNodes.filter((node) => node.status === "active" || node.status === "disputed");
|
|
3482
|
+
const queryTokens = [...new Set(searchTokens(query))];
|
|
3483
|
+
const fieldValues = (node) => [
|
|
3484
|
+
["name", node.name],
|
|
3485
|
+
["aliases", node.aliases.join(" ")],
|
|
3486
|
+
["tags", (node.tags ?? []).join(" ")],
|
|
3487
|
+
["type", node.type],
|
|
3488
|
+
["currentState", node.currentState],
|
|
3489
|
+
["facts", node.facts.map((fact) => `${fact.key} ${Array.isArray(fact.value) ? fact.value.join(" ") : fact.value}`).join(" ")],
|
|
3490
|
+
["relations", this.graphEdges.filter((edge) => edge.fromNodeId === node.id || edge.toNodeId === node.id).map(({ relation }) => relation).join(" ")]
|
|
3491
|
+
];
|
|
3482
3492
|
const ranked = bm25Rank(candidates, query, (node) => weightedSearchTokens([
|
|
3483
3493
|
[node.name, 6],
|
|
3484
3494
|
[node.aliases.join(" "), 5],
|
|
@@ -3487,9 +3497,28 @@ var StrataGate = class _StrataGate {
|
|
|
3487
3497
|
[node.currentState, 4],
|
|
3488
3498
|
[node.facts.map((fact) => `${fact.key} ${Array.isArray(fact.value) ? fact.value.join(" ") : fact.value}`).join(" "), 4],
|
|
3489
3499
|
[this.graphEdges.filter((edge) => edge.fromNodeId === node.id || edge.toNodeId === node.id).map(({ relation }) => relation).join(" "), 3]
|
|
3490
|
-
])).
|
|
3500
|
+
])).filter(({ item }) => {
|
|
3501
|
+
const fields = fieldValues(item);
|
|
3502
|
+
const matches = fields.filter(([, value]) => {
|
|
3503
|
+
const haystack = new Set(searchTokens(value));
|
|
3504
|
+
return queryTokens.some((token) => haystack.has(token));
|
|
3505
|
+
}).map(([field]) => field);
|
|
3506
|
+
if (!matches.some((field) => field !== "relations")) return false;
|
|
3507
|
+
return matches.some((field) => field !== "relations");
|
|
3508
|
+
}).slice(0, Math.max(1, Math.min(20, limit)));
|
|
3491
3509
|
if (searchTokens(query).length > 0 && ranked.length === 0) return [];
|
|
3492
|
-
return ranked.map(({ item: node, score }) =>
|
|
3510
|
+
return ranked.map(({ item: node, score }) => {
|
|
3511
|
+
const matchedFields = fieldValues(node).filter(([, value]) => {
|
|
3512
|
+
const haystack = new Set(searchTokens(value));
|
|
3513
|
+
return queryTokens.some((token) => haystack.has(token));
|
|
3514
|
+
}).map(([field]) => field);
|
|
3515
|
+
return {
|
|
3516
|
+
node,
|
|
3517
|
+
score,
|
|
3518
|
+
matchedFields,
|
|
3519
|
+
matchReason: `Lexical match in ${matchedFields.join(", ") || "indexed fields"}; score is ranking-only.`
|
|
3520
|
+
};
|
|
3521
|
+
});
|
|
3493
3522
|
}
|
|
3494
3523
|
requireGraphProjectionJob(id) {
|
|
3495
3524
|
const job = this.graphProjectionJobs.get(id);
|
|
@@ -4718,7 +4747,7 @@ var StrataGateRuntime = class {
|
|
|
4718
4747
|
return this.batch(session, results.map(({ event }) => ({
|
|
4719
4748
|
ref: `event:${event.id}`,
|
|
4720
4749
|
target: { eventIds: [event.id], elementIds: [] }
|
|
4721
|
-
})), results);
|
|
4750
|
+
})), results.map(({ event, score }) => compactEvent(event, score)));
|
|
4722
4751
|
}
|
|
4723
4752
|
async searchElements(session, query, options = {}) {
|
|
4724
4753
|
await this.flush();
|
|
@@ -4726,7 +4755,18 @@ var StrataGateRuntime = class {
|
|
|
4726
4755
|
return this.batch(session, results.map((result) => ({
|
|
4727
4756
|
ref: `element:${result.elementId}:fact:${result.id}`,
|
|
4728
4757
|
target: { eventIds: [], elementIds: [result.elementId] }
|
|
4729
|
-
})), results)
|
|
4758
|
+
})), results.map((result) => ({
|
|
4759
|
+
id: result.id,
|
|
4760
|
+
elementId: result.elementId,
|
|
4761
|
+
name: result.name,
|
|
4762
|
+
type: result.type,
|
|
4763
|
+
factKey: result.fact.key,
|
|
4764
|
+
value: Array.isArray(result.fact.value) ? result.fact.value.join(", ") : result.fact.value,
|
|
4765
|
+
validFrom: result.fact.validFrom,
|
|
4766
|
+
validTo: result.fact.validTo,
|
|
4767
|
+
rankScore: result.score,
|
|
4768
|
+
scoreMeaning: "Ranking-only BM25/RRF score; not confidence or factual accuracy."
|
|
4769
|
+
})));
|
|
4730
4770
|
}
|
|
4731
4771
|
async searchRaw(session, query, limit, scope = "namespace") {
|
|
4732
4772
|
await this.flush();
|
|
@@ -4736,7 +4776,7 @@ var StrataGateRuntime = class {
|
|
|
4736
4776
|
return this.batch(session, results.map((result, index) => ({
|
|
4737
4777
|
ref: `raw:${result.blockId}:${result.message.id}:${index}`,
|
|
4738
4778
|
target: { eventIds: [], elementIds: [] }
|
|
4739
|
-
})), results, { scope, namespace: this.namespaceFor(session), threadId });
|
|
4779
|
+
})), results.map(compactRawHit), { scope, namespace: this.namespaceFor(session), threadId });
|
|
4740
4780
|
}
|
|
4741
4781
|
async blocks(session, scope = "session") {
|
|
4742
4782
|
await this.flush();
|
|
@@ -5244,7 +5284,7 @@ var StrataGateRuntime = class {
|
|
|
5244
5284
|
return this.batch(session, results.map(({ node }) => ({
|
|
5245
5285
|
ref: `graph-node:${node.id}`,
|
|
5246
5286
|
target: { eventIds: node.sourceEventIds, elementIds: [] }
|
|
5247
|
-
})), results);
|
|
5287
|
+
})), results.map(({ node, score, matchedFields, matchReason }) => compactGraphNode(node, score, matchedFields, matchReason)));
|
|
5248
5288
|
}
|
|
5249
5289
|
async expandGraphNode(session, id) {
|
|
5250
5290
|
await this.flush();
|
|
@@ -5444,6 +5484,67 @@ function renderBlockSurfaceMessage(context) {
|
|
|
5444
5484
|
context.content
|
|
5445
5485
|
].join("\n");
|
|
5446
5486
|
}
|
|
5487
|
+
function compactTemporal(event) {
|
|
5488
|
+
const temporal = event.temporal;
|
|
5489
|
+
return Object.fromEntries(Object.entries({
|
|
5490
|
+
mentionedAt: temporal.mentionedAt,
|
|
5491
|
+
happenedStart: temporal.happenedStart,
|
|
5492
|
+
happenedEnd: temporal.happenedEnd,
|
|
5493
|
+
precision: temporal.precision,
|
|
5494
|
+
status: temporal.status,
|
|
5495
|
+
eventType: temporal.eventType
|
|
5496
|
+
}).filter(([, value]) => value !== void 0));
|
|
5497
|
+
}
|
|
5498
|
+
function compactText2(value, limit = 800) {
|
|
5499
|
+
return value.replace(/\s+/gu, " ").trim().slice(0, limit);
|
|
5500
|
+
}
|
|
5501
|
+
function compactEvent(event, score) {
|
|
5502
|
+
return {
|
|
5503
|
+
id: event.id,
|
|
5504
|
+
title: compactText2(event.title, 240),
|
|
5505
|
+
summary: compactText2(event.summary),
|
|
5506
|
+
sourceTime: event.temporal.happenedStart ?? event.temporal.mentionedAt ?? event.createdAt,
|
|
5507
|
+
temporal: compactTemporal(event),
|
|
5508
|
+
sourceBlockId: event.sourceBlockId,
|
|
5509
|
+
status: event.status,
|
|
5510
|
+
scope: event.scope,
|
|
5511
|
+
criticality: event.criticality,
|
|
5512
|
+
rankScore: score,
|
|
5513
|
+
scoreMeaning: "Ranking-only BM25/RRF score; not confidence, probability, or factual accuracy."
|
|
5514
|
+
};
|
|
5515
|
+
}
|
|
5516
|
+
function compactGraphNode(node, score, matchedFields, matchReason) {
|
|
5517
|
+
return {
|
|
5518
|
+
id: node.id,
|
|
5519
|
+
name: node.name,
|
|
5520
|
+
type: node.type,
|
|
5521
|
+
aliases: node.aliases.map((alias) => compactText2(alias, 160)),
|
|
5522
|
+
currentState: compactText2(node.currentState, 500),
|
|
5523
|
+
status: node.status,
|
|
5524
|
+
rankScore: score,
|
|
5525
|
+
...matchedFields ? { matchedFields } : {},
|
|
5526
|
+
...matchReason ? { matchReason } : {},
|
|
5527
|
+
scoreMeaning: "Ranking-only BM25/RRF score; not confidence, probability, or factual accuracy."
|
|
5528
|
+
};
|
|
5529
|
+
}
|
|
5530
|
+
function compactRawHit(result) {
|
|
5531
|
+
const message = {
|
|
5532
|
+
id: result.message.id,
|
|
5533
|
+
role: result.message.role,
|
|
5534
|
+
content: compactText2(result.message.content, 500),
|
|
5535
|
+
createdAt: result.message.createdAt,
|
|
5536
|
+
...result.message.threadId ? { threadId: result.message.threadId } : {}
|
|
5537
|
+
};
|
|
5538
|
+
return {
|
|
5539
|
+
id: result.message.id,
|
|
5540
|
+
blockId: result.blockId,
|
|
5541
|
+
turnRange: result.turnRange,
|
|
5542
|
+
message,
|
|
5543
|
+
sourceTime: result.message.createdAt,
|
|
5544
|
+
...result.message.threadId ? { threadId: result.message.threadId } : {},
|
|
5545
|
+
detailHint: "Use memory_expand_block with blockId for complete block/source details."
|
|
5546
|
+
};
|
|
5547
|
+
}
|
|
5447
5548
|
function currentBlockSurfaceMessages(session) {
|
|
5448
5549
|
const blocks = /* @__PURE__ */ new Map();
|
|
5449
5550
|
if (!session.surface?.nodes) return blocks;
|
|
@@ -5588,7 +5689,7 @@ function sessionOf(exec) {
|
|
|
5588
5689
|
function registerMemoryTools(ctx, runtime) {
|
|
5589
5690
|
ctx.tools.register(defineTool({
|
|
5590
5691
|
name: "memory_search_events",
|
|
5591
|
-
description: "Search durable StrataGate event memories. Returns a
|
|
5692
|
+
description: "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.",
|
|
5592
5693
|
parameters: {
|
|
5593
5694
|
query: { type: "string", required: true, description: "What historical decision, event, preference, or outcome to find." },
|
|
5594
5695
|
limit: { type: "integer", description: "Maximum results, 1-20." },
|
|
@@ -5606,7 +5707,7 @@ function registerMemoryTools(ctx, runtime) {
|
|
|
5606
5707
|
}));
|
|
5607
5708
|
ctx.tools.register(defineTool({
|
|
5608
5709
|
name: "memory_search_graph",
|
|
5609
|
-
description: "Search the current Event-backed Knowledge Graph for people, projects, organizations, tools, places, facts, and relations. Returns
|
|
5710
|
+
description: "Search the current Event-backed Knowledge Graph for people, projects, organizations, tools, places, facts, and relations. Returns compact node cards with matchedFields/matchReason; call memory_expand_graph_node for complete facts and edges. rankScore is BM25/RRF ordering only, never confidence or factual accuracy. Results are independently assessable.",
|
|
5610
5711
|
parameters: {
|
|
5611
5712
|
query: { type: "string", required: true },
|
|
5612
5713
|
limit: { type: "integer", description: "Maximum results, 1-20." }
|
|
@@ -5623,7 +5724,7 @@ function registerMemoryTools(ctx, runtime) {
|
|
|
5623
5724
|
}));
|
|
5624
5725
|
ctx.tools.register(defineTool({
|
|
5625
5726
|
name: "memory_search_elements",
|
|
5626
|
-
description: "Deprecated compatibility search for legacy Element-card data. Prefer memory_search_graph.",
|
|
5727
|
+
description: "Deprecated compatibility search for legacy Element-card data. Returns compact fact hits; rankScore is BM25/RRF ordering only, never confidence or factual accuracy. Prefer memory_search_graph.",
|
|
5627
5728
|
parameters: {
|
|
5628
5729
|
query: { type: "string", required: true },
|
|
5629
5730
|
limit: { type: "integer" },
|
|
@@ -5639,7 +5740,7 @@ function registerMemoryTools(ctx, runtime) {
|
|
|
5639
5740
|
}));
|
|
5640
5741
|
ctx.tools.register(defineTool({
|
|
5641
5742
|
name: "memory_search_raw",
|
|
5642
|
-
description: "Search
|
|
5743
|
+
description: "Search archived messages when summarized memories are insufficient. Returns compact raw hits (message id, blockId, excerpt, role, and time); use memory_expand_block with blockId for complete source details. By default searches the whole current namespace; use scope=session for the active thread. Returns evidence refs and batchId for assessment.",
|
|
5643
5744
|
parameters: {
|
|
5644
5745
|
query: { type: "string", required: true },
|
|
5645
5746
|
limit: { type: "integer" },
|