@jungjaehoon/mama-core 5.0.0 → 5.1.0
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/README.md +1 -1
- package/dist/api/catalog.js +1 -1
- package/dist/knowledge/access.js +1 -1
- package/dist/knowledge/index.d.ts +1 -1
- package/dist/knowledge/index.js +2 -1
- package/dist/knowledge/search.d.ts +6 -1
- package/dist/knowledge/search.js +17 -11
- package/dist/memory/api.d.ts +1 -1
- package/dist/memory/api.js +61 -15
- package/dist/memory/provenance-live.js +1 -1
- package/dist/memory/types.d.ts +1 -1
- package/dist/memory/types.js +1 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ The shared engine for storage, records and revisions, evidence links, memory, se
|
|
|
4
4
|
runtime drivers. Consumers supply their own database, principals, source access and product
|
|
5
5
|
vocabulary through public exports. Core does not require the MAMA OS daemon.
|
|
6
6
|
|
|
7
|
-
Version **5.
|
|
7
|
+
Version **5.1.0**; Node.js 22.13+. This README describes the current rebuild checkout.
|
|
8
8
|
See [architecture](../../docs/explanation/architecture.md) and
|
|
9
9
|
[the shared-engine goal](../../INTENT.md).
|
|
10
10
|
|
package/dist/api/catalog.js
CHANGED
|
@@ -1367,7 +1367,7 @@ function coreActionRegistrations(knowledge, adapter, deps) {
|
|
|
1367
1367
|
memoryId: typeof body.memory_id === 'string' ? body.memory_id : '',
|
|
1368
1368
|
status,
|
|
1369
1369
|
reason: typeof body.reason === 'string' ? body.reason : '',
|
|
1370
|
-
}, { ...writeAccess, scopes }, requiredOperationId(context, 'memory.retire'));
|
|
1370
|
+
}, { ...writeAccess, scopes }, requiredOperationId(context, 'memory.retire'), context.session);
|
|
1371
1371
|
recordWriteReceipt(context, 'memory.retire', retired.id);
|
|
1372
1372
|
return retired;
|
|
1373
1373
|
},
|
package/dist/knowledge/access.js
CHANGED
|
@@ -17,7 +17,7 @@ const tableColumnCache = new WeakMap();
|
|
|
17
17
|
// Keep memory-truth quarantine semantics excluded for legacy/backcompat rows even though the
|
|
18
18
|
// decisions.status terminal states: 'superseded' is history a caller holding
|
|
19
19
|
// scope may read under includeReplaced; the rest are holds excluded always.
|
|
20
|
-
const RETIRED_MEMORY_STATUSES = new Set(['
|
|
20
|
+
const RETIRED_MEMORY_STATUSES = new Set(['contradicted', 'stale']);
|
|
21
21
|
class TwinRefNotVisibleError extends Error {
|
|
22
22
|
constructor(ref) {
|
|
23
23
|
super(`Twin ref is not visible to requested visibility: ${ref.kind}:${ref.id}`);
|
|
@@ -19,7 +19,7 @@ export { observationVersionId, appendObservationVersion, getObservationVersion,
|
|
|
19
19
|
export { createWork, readWork, reviseWork, withdrawWork } from './commitments.js';
|
|
20
20
|
export { parseExactDueAt, assertIsoDate, assertWorkPatchValues, WORK_PATCH_DEADLINE_PATTERN, WORK_PATCH_DUE_AT_PATTERN, type ParsedExactDueAt, } from './work-dates.js';
|
|
21
21
|
export type { CommitmentPage, CommitmentChainEntry, CommitmentRevision, CommitmentView, CreateWorkCommand, ReviseWorkCommand, WithdrawWorkCommand, WorkRead, WorkWriteResult, } from './commitments.js';
|
|
22
|
-
export { vectorSearch, fts5Search } from './search.js';
|
|
22
|
+
export { vectorSearch, fts5Search, RECALL_EXCLUDED_STATUSES } from './search.js';
|
|
23
23
|
export { queryDecisionGraph, querySemanticEdges, STATED_DECISION_EDGES, getGraphNeighborhood, getGraphPaths, getGraphTimeline, queryGraph, AgentGraphValidationError, type AgentGraphAdapter, type AgentGraphEdgeFilters, type AgentGraphResult, type AgentGraphCurrentProjection, type AgentGraphPath, type AgentGraphTimelineEvent, type AgentGraphTimelineMemoryEvent, type AgentGraphTimelineCaseEvent, type AgentGraphTimelineRawEvent, type AgentGraphTimelineEdgeEvent, type GraphNeighborhoodInput, type GraphPathsInput, type GraphPathsResult, type GraphTimelineInput, type GraphTimelineResult, } from './graph-query.js';
|
|
24
24
|
export type { SourceIngestCommand, SourceIngestReceipt } from './source-ingest.js';
|
|
25
25
|
export interface KnowledgeOptions extends JudgmentKnowledgeOptions {
|
package/dist/knowledge/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AgentGraphValidationError = exports.queryGraph = exports.getGraphTimeline = exports.getGraphPaths = exports.getGraphNeighborhood = exports.STATED_DECISION_EDGES = exports.querySemanticEdges = exports.queryDecisionGraph = exports.fts5Search = exports.vectorSearch = exports.WORK_PATCH_DUE_AT_PATTERN = exports.WORK_PATCH_DEADLINE_PATTERN = exports.assertWorkPatchValues = exports.assertIsoDate = exports.parseExactDueAt = exports.withdrawWork = exports.reviseWork = exports.readWork = exports.createWork = exports.isObservationVisibilityRowVisible = exports.isObservationVersionVisible = exports.readObservationVersion = exports.searchOwnerObservationVersions = exports.getObservationVersion = exports.appendObservationVersion = exports.observationVersionId = exports.correctIdentity = exports.ingestSource = exports.TWIN_REF_KINDS = exports.TWIN_EDGE_TYPES = exports.TWIN_EDGE_SOURCES = exports.TwinRefNotVisibleError = exports.visibleTwinRefKeysRecursive = exports.visibleTwinRefKeys = exports.listVisibleTwinEdgesForRefs = exports.isChannelGranted = exports.channelGrantClause = exports.assertTwinRefsVisible = exports.linkEdgeId = exports.findLink = exports.appendLink = exports.mapTwinEdgeRow = exports.listTwinEdgesForRefs = exports.getTwinEdge = exports.appendJudgment = exports.JudgmentError = exports.WORK_RECLASSIFY_DISPOSITIONS = exports.judgmentRecordId = void 0;
|
|
3
|
+
exports.AgentGraphValidationError = exports.queryGraph = exports.getGraphTimeline = exports.getGraphPaths = exports.getGraphNeighborhood = exports.STATED_DECISION_EDGES = exports.querySemanticEdges = exports.queryDecisionGraph = exports.RECALL_EXCLUDED_STATUSES = exports.fts5Search = exports.vectorSearch = exports.WORK_PATCH_DUE_AT_PATTERN = exports.WORK_PATCH_DEADLINE_PATTERN = exports.assertWorkPatchValues = exports.assertIsoDate = exports.parseExactDueAt = exports.withdrawWork = exports.reviseWork = exports.readWork = exports.createWork = exports.isObservationVisibilityRowVisible = exports.isObservationVersionVisible = exports.readObservationVersion = exports.searchOwnerObservationVersions = exports.getObservationVersion = exports.appendObservationVersion = exports.observationVersionId = exports.correctIdentity = exports.ingestSource = exports.TWIN_REF_KINDS = exports.TWIN_EDGE_TYPES = exports.TWIN_EDGE_SOURCES = exports.TwinRefNotVisibleError = exports.visibleTwinRefKeysRecursive = exports.visibleTwinRefKeys = exports.listVisibleTwinEdgesForRefs = exports.isChannelGranted = exports.channelGrantClause = exports.assertTwinRefsVisible = exports.linkEdgeId = exports.findLink = exports.appendLink = exports.mapTwinEdgeRow = exports.listTwinEdgesForRefs = exports.getTwinEdge = exports.appendJudgment = exports.JudgmentError = exports.WORK_RECLASSIFY_DISPOSITIONS = exports.judgmentRecordId = void 0;
|
|
4
4
|
exports.createKnowledge = createKnowledge;
|
|
5
5
|
const links_js_1 = require("./links.js");
|
|
6
6
|
const judgments_js_1 = require("./judgments.js");
|
|
@@ -62,6 +62,7 @@ Object.defineProperty(exports, "WORK_PATCH_DUE_AT_PATTERN", { enumerable: true,
|
|
|
62
62
|
var search_js_1 = require("./search.js");
|
|
63
63
|
Object.defineProperty(exports, "vectorSearch", { enumerable: true, get: function () { return search_js_1.vectorSearch; } });
|
|
64
64
|
Object.defineProperty(exports, "fts5Search", { enumerable: true, get: function () { return search_js_1.fts5Search; } });
|
|
65
|
+
Object.defineProperty(exports, "RECALL_EXCLUDED_STATUSES", { enumerable: true, get: function () { return search_js_1.RECALL_EXCLUDED_STATUSES; } });
|
|
65
66
|
var graph_query_js_2 = require("./graph-query.js");
|
|
66
67
|
Object.defineProperty(exports, "queryDecisionGraph", { enumerable: true, get: function () { return graph_query_js_2.queryDecisionGraph; } });
|
|
67
68
|
Object.defineProperty(exports, "querySemanticEdges", { enumerable: true, get: function () { return graph_query_js_2.querySemanticEdges; } });
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { DatabaseInstance, DecisionRecord } from '../db-manager.js';
|
|
10
10
|
import type { MemoryKindFilter } from '../memory/types.js';
|
|
11
|
+
/** Statuses default recall leaves out; history (`includeHistory`) shows them. */
|
|
12
|
+
export declare const RECALL_EXCLUDED_STATUSES: readonly ["superseded", "contradicted", "stale"];
|
|
11
13
|
/**
|
|
12
14
|
* Brute-force cosine similarity search over stored embeddings.
|
|
13
15
|
*
|
|
@@ -31,7 +33,10 @@ export declare function vectorSearch(adapter: DatabaseInstance, queryEmbedding:
|
|
|
31
33
|
* @param limit - Max rows to return
|
|
32
34
|
* @returns Matching decision IDs with BM25 rank scores
|
|
33
35
|
*/
|
|
34
|
-
export declare function fts5Search(adapter: DatabaseInstance, query: string, limit?: number, kind?: MemoryKindFilter
|
|
36
|
+
export declare function fts5Search(adapter: DatabaseInstance, query: string, limit?: number, kind?: MemoryKindFilter, exclude?: {
|
|
37
|
+
statuses?: readonly string[];
|
|
38
|
+
amendments?: boolean;
|
|
39
|
+
}): Promise<{
|
|
35
40
|
id: string;
|
|
36
41
|
rank: number;
|
|
37
42
|
}[]>;
|
package/dist/knowledge/search.js
CHANGED
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
* @module knowledge/search
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.RECALL_EXCLUDED_STATUSES = void 0;
|
|
11
12
|
exports.vectorSearch = vectorSearch;
|
|
12
13
|
exports.fts5Search = fts5Search;
|
|
14
|
+
/** Statuses default recall leaves out; history (`includeHistory`) shows them. */
|
|
15
|
+
exports.RECALL_EXCLUDED_STATUSES = ['superseded', 'contradicted', 'stale'];
|
|
13
16
|
/**
|
|
14
17
|
* Brute-force cosine similarity search over stored embeddings.
|
|
15
18
|
*
|
|
@@ -59,7 +62,7 @@ async function vectorSearch(adapter, queryEmbedding, limit = 5, threshold = 0.7,
|
|
|
59
62
|
* @param limit - Max rows to return
|
|
60
63
|
* @returns Matching decision IDs with BM25 rank scores
|
|
61
64
|
*/
|
|
62
|
-
async function fts5Search(adapter, query, limit = 10, kind) {
|
|
65
|
+
async function fts5Search(adapter, query, limit = 10, kind, exclude) {
|
|
63
66
|
// An absent FTS table is a real answer - no rows. A failing adapter is not,
|
|
64
67
|
// so this lookup is left unguarded and its errors reach the caller.
|
|
65
68
|
const tableCheck = adapter
|
|
@@ -68,24 +71,27 @@ async function fts5Search(adapter, query, limit = 10, kind) {
|
|
|
68
71
|
if (!tableCheck)
|
|
69
72
|
return [];
|
|
70
73
|
// Query execution - let errors propagate to the caller
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const kinds = Array.isArray(kind) ? kind : kind === undefined ? [] : [kind];
|
|
75
|
+
const kindClause = kinds.length === 0 ? '' : `AND d.kind IN (${kinds.map(() => '?').join(', ')})`;
|
|
76
|
+
// Excluded rows are left out before LIMIT, so they cannot fill the pool ahead of rows that stay.
|
|
77
|
+
const statuses = exclude?.statuses ?? [];
|
|
78
|
+
const statusClause = statuses.length === 0
|
|
79
|
+
? ''
|
|
80
|
+
: `AND (d.status IS NULL OR d.status NOT IN (${statuses.map(() => '?').join(', ')}))`;
|
|
81
|
+
const amendmentClause = exclude?.amendments
|
|
82
|
+
? "AND json_extract(d.payload_json, '$.amended') IS NULL"
|
|
83
|
+
: '';
|
|
76
84
|
const stmt = adapter.prepare(`
|
|
77
85
|
SELECT d.id, rank
|
|
78
86
|
FROM decisions_fts
|
|
79
87
|
JOIN decisions d ON decisions_fts.rowid = d.rowid
|
|
80
88
|
WHERE decisions_fts MATCH ?
|
|
81
89
|
${kindClause}
|
|
90
|
+
${statusClause}
|
|
91
|
+
${amendmentClause}
|
|
82
92
|
ORDER BY rank
|
|
83
93
|
LIMIT ?
|
|
84
94
|
`);
|
|
85
|
-
return
|
|
86
|
-
? stmt.all(query, ...kind, limit)
|
|
87
|
-
: kind === undefined
|
|
88
|
-
? stmt.all(query, limit)
|
|
89
|
-
: stmt.all(query, kind, limit));
|
|
95
|
+
return stmt.all(query, ...kinds, ...statuses, limit);
|
|
90
96
|
}
|
|
91
97
|
//# sourceMappingURL=search.js.map
|
package/dist/memory/api.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ export declare function retireMemoryRecord(adapter: DatabaseInstance, input: {
|
|
|
76
76
|
memoryId: string;
|
|
77
77
|
status: MemoryRetirementStatus;
|
|
78
78
|
reason: string;
|
|
79
|
-
}, access: JudgmentAccess, commandId: string): Promise<{
|
|
79
|
+
}, access: JudgmentAccess, commandId: string, session?: ActionSessionFacts): Promise<{
|
|
80
80
|
success: true;
|
|
81
81
|
id: string;
|
|
82
82
|
status: MemoryRetirementStatus;
|
package/dist/memory/api.js
CHANGED
|
@@ -713,7 +713,7 @@ async function saveLegacyMemory(adapter, input, legacy, access) {
|
|
|
713
713
|
return saveMemoryInternal(adapter, clean, provenance, effectiveAccess, legacy);
|
|
714
714
|
}
|
|
715
715
|
/** Append an access-checked status amendment for one stored memory record. */
|
|
716
|
-
async function retireMemoryRecord(adapter, input, access, commandId) {
|
|
716
|
+
async function retireMemoryRecord(adapter, input, access, commandId, session) {
|
|
717
717
|
const id = input.memoryId.trim();
|
|
718
718
|
const reason = input.reason.trim();
|
|
719
719
|
if (!id)
|
|
@@ -729,11 +729,30 @@ async function retireMemoryRecord(adapter, input, access, commandId) {
|
|
|
729
729
|
}
|
|
730
730
|
const admittedScopes = record.scopes.filter((recordScope) => access.scopes.some((scope) => scope.kind === recordScope.kind && scope.id === recordScope.id));
|
|
731
731
|
const summary = `Status '${input.status}' applied to ${id}: ${reason}`;
|
|
732
|
+
// Who retired it, stated by the host as for a save, so a retirement can be traced to its turn.
|
|
733
|
+
const provenance = (0, provenance_js_1.normalizeMemoryWriteProvenance)({
|
|
734
|
+
actor: session?.actor ?? 'main_agent',
|
|
735
|
+
agent_id: access.agentId,
|
|
736
|
+
model_run_id: session?.modelRunId,
|
|
737
|
+
envelope_hash: session?.envelopeHash,
|
|
738
|
+
tool_name: session?.toolName,
|
|
739
|
+
gateway_call_id: session?.gatewayCallId,
|
|
740
|
+
context_packet_id: session?.contextPacketId,
|
|
741
|
+
source_turn_id: session?.sourceTurnId,
|
|
742
|
+
source_message_ref: session?.sourceMessageRef,
|
|
743
|
+
source_refs: session?.sourceRefs ? [...session.sourceRefs] : undefined,
|
|
744
|
+
});
|
|
732
745
|
const receipt = await (0, index_js_1.appendJudgment)({
|
|
733
746
|
commandId,
|
|
734
747
|
topic: `judgment/${id}`,
|
|
735
748
|
summary,
|
|
736
749
|
recordKind: 'judgment',
|
|
750
|
+
sourceRefs: provenance.source_refs,
|
|
751
|
+
provenance: provenance.provenance,
|
|
752
|
+
agentId: provenance.agent_id,
|
|
753
|
+
modelRunId: provenance.model_run_id,
|
|
754
|
+
envelopeHash: provenance.envelope_hash,
|
|
755
|
+
gatewayCallId: provenance.gateway_call_id,
|
|
737
756
|
payload: { amended: id, status: input.status, reason },
|
|
738
757
|
scopes: admittedScopes,
|
|
739
758
|
links: [{ relation: 'amends', target: { kind: 'memory', id } }],
|
|
@@ -747,12 +766,15 @@ async function buildProfile(adapter, scopes) {
|
|
|
747
766
|
const records = await loadScopedMemories(adapter, scopes);
|
|
748
767
|
return (0, profile_builder_js_1.classifyProfileEntries)(records);
|
|
749
768
|
}
|
|
750
|
-
const EXCLUDED_STATUSES = new Set(
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
769
|
+
const EXCLUDED_STATUSES = new Set(search_js_1.RECALL_EXCLUDED_STATUSES);
|
|
770
|
+
/** The ids among these that only amend another record (a retirement or an outcome change). */
|
|
771
|
+
function amendmentIds(adapter, ids) {
|
|
772
|
+
const rows = adapter
|
|
773
|
+
.prepare(`SELECT id FROM decisions WHERE id IN (${ids.map(() => '?').join(',')})
|
|
774
|
+
AND json_extract(payload_json, '$.amended') IS NOT NULL`)
|
|
775
|
+
.all(...ids);
|
|
776
|
+
return new Set(rows.map((row) => row.id));
|
|
777
|
+
}
|
|
756
778
|
async function recallMemory(adapter, query, options = {}) {
|
|
757
779
|
const bundle = (0, types_js_1.createEmptyRecallBundle)(query);
|
|
758
780
|
const searchOptions = (0, search_quality_js_1.normalizeSearchQualityOptions)(options);
|
|
@@ -930,7 +952,7 @@ async function recallMemory(adapter, query, options = {}) {
|
|
|
930
952
|
.map((t) => stemToken(t))
|
|
931
953
|
.filter((t) => !FTS5_NOISE_WORDS.has(t));
|
|
932
954
|
const ftsQuery = ftsTokens.length > 0 ? ftsTokens.join(' OR ') : query;
|
|
933
|
-
const ftsResults = await (0, search_js_1.fts5Search)(searchAdapter, ftsQuery, lexicalLimit, options.kind);
|
|
955
|
+
const ftsResults = await (0, search_js_1.fts5Search)(searchAdapter, ftsQuery, lexicalLimit, options.kind, options.includeHistory ? undefined : { statuses: [...EXCLUDED_STATUSES], amendments: true });
|
|
934
956
|
if (ftsResults.length > 0) {
|
|
935
957
|
const adapter = searchAdapter;
|
|
936
958
|
const fallbackSource = {
|
|
@@ -1012,6 +1034,10 @@ async function recallMemory(adapter, query, options = {}) {
|
|
|
1012
1034
|
if (options.kind !== undefined) {
|
|
1013
1035
|
lexicalRecords = lexicalRecords.filter((r) => matchesKind(r.kind));
|
|
1014
1036
|
}
|
|
1037
|
+
if (!options.includeHistory && lexicalRecords.length > 0) {
|
|
1038
|
+
const amendments = amendmentIds(adapter, lexicalRecords.map((r) => r.id));
|
|
1039
|
+
lexicalRecords = lexicalRecords.filter((r) => !amendments.has(r.id));
|
|
1040
|
+
}
|
|
1015
1041
|
lexicalCandidates = buildLexicalCandidates(lexicalRecords, query);
|
|
1016
1042
|
if (subQueries.length > 1) {
|
|
1017
1043
|
for (const sq of subQueries.slice(1)) {
|
|
@@ -1187,6 +1213,15 @@ async function recallMemory(adapter, query, options = {}) {
|
|
|
1187
1213
|
];
|
|
1188
1214
|
});
|
|
1189
1215
|
fusedHits = fusedHits.filter((hit) => hit.source_type !== 'decision' || acceptedPrimaryIds.has(hit.source_id));
|
|
1216
|
+
// A retirement or an outcome change audits another record; it is not a belief. Default recall
|
|
1217
|
+
// leaves it out and history shows it. Only the host writers put `amended` in a payload.
|
|
1218
|
+
if (!options.includeHistory && matched.length > 0) {
|
|
1219
|
+
const amendments = amendmentIds(adapter, matched.map((record) => record.id));
|
|
1220
|
+
if (amendments.size > 0) {
|
|
1221
|
+
matched = matched.filter((record) => !amendments.has(record.id));
|
|
1222
|
+
fusedHits = fusedHits.filter((hit) => hit.source_type !== 'decision' || !amendments.has(hit.source_id));
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1190
1225
|
// Honor options.limit on the final memories (matched is RRF-rank-sorted, canonical
|
|
1191
1226
|
// dual-write appends last). Without this cap the full fusion set (hundreds of records)
|
|
1192
1227
|
// flowed into bundle.memories AND the per-record enrichment SQL loops below.
|
|
@@ -1198,14 +1233,20 @@ async function recallMemory(adapter, query, options = {}) {
|
|
|
1198
1233
|
const cappedIds = new Set(matched.map((record) => record.id));
|
|
1199
1234
|
fusedHits = fusedHits.filter((hit) => hit.source_type !== 'decision' || cappedIds.has(hit.source_id));
|
|
1200
1235
|
}
|
|
1201
|
-
//
|
|
1202
|
-
//
|
|
1203
|
-
//
|
|
1204
|
-
// excluded from search. This recovers their key information so it is not lost.
|
|
1236
|
+
// Superseded records are excluded from search, so an active record carries what it replaced:
|
|
1237
|
+
// the reader sees the correction and what it corrected. A predecessor is shown only inside the
|
|
1238
|
+
// reader's scopes, and marked as replaced.
|
|
1205
1239
|
if (matched.length > 0) {
|
|
1206
1240
|
const stmtChain = adapter.prepare(`SELECT id, summary, decision FROM decisions WHERE superseded_by = ?`);
|
|
1241
|
+
const readerScopes = options.scopes && options.scopes.length > 0
|
|
1242
|
+
? new Set(options.scopes.map((scope) => `${scope.kind}:${scope.id}`))
|
|
1243
|
+
: null;
|
|
1207
1244
|
for (const record of matched) {
|
|
1208
|
-
|
|
1245
|
+
let predecessors = stmtChain.all(record.id);
|
|
1246
|
+
if (readerScopes && predecessors.length > 0) {
|
|
1247
|
+
const scopeMap = batchLoadScopes(adapter, predecessors.map((predecessor) => predecessor.id));
|
|
1248
|
+
predecessors = predecessors.filter((predecessor) => (scopeMap.get(predecessor.id) ?? []).some((scope) => readerScopes.has(`${scope.kind}:${scope.id}`)));
|
|
1249
|
+
}
|
|
1209
1250
|
if (predecessors.length > 0) {
|
|
1210
1251
|
const extra = predecessors
|
|
1211
1252
|
.map((p) => String(p.summary ?? p.decision ?? ''))
|
|
@@ -1213,8 +1254,8 @@ async function recallMemory(adapter, query, options = {}) {
|
|
|
1213
1254
|
.join(' | ');
|
|
1214
1255
|
if (extra) {
|
|
1215
1256
|
record.details = record.details
|
|
1216
|
-
? `${record.details}\n[
|
|
1217
|
-
: `[
|
|
1257
|
+
? `${record.details}\n[Replaced by this record] ${extra}`
|
|
1258
|
+
: `[Replaced by this record] ${extra}`;
|
|
1218
1259
|
}
|
|
1219
1260
|
}
|
|
1220
1261
|
}
|
|
@@ -1243,6 +1284,11 @@ async function recallMemory(adapter, query, options = {}) {
|
|
|
1243
1284
|
const status = row?.status || '';
|
|
1244
1285
|
return matchesKind(row?.kind) && (!status || !EXCLUDED_STATUSES.has(status));
|
|
1245
1286
|
});
|
|
1287
|
+
// A link an agent stated can point at a retirement or an outcome change; it stays out too.
|
|
1288
|
+
if (expandedOnly.length > 0) {
|
|
1289
|
+
const amendments = amendmentIds(adapter, expandedOnly.map((e) => e.id));
|
|
1290
|
+
expandedOnly = expandedOnly.filter((e) => !amendments.has(e.id));
|
|
1291
|
+
}
|
|
1246
1292
|
}
|
|
1247
1293
|
else if (options.kind !== undefined) {
|
|
1248
1294
|
expandedOnly = expandedOnly.filter((e) => {
|
|
@@ -24,7 +24,7 @@ exports.OBSERVATION_COLUMNS = `observation_id AS event_index_id, source AS sourc
|
|
|
24
24
|
* Statuses every memory read path excludes (source-readers.ts:293, and recall's own
|
|
25
25
|
* history exclusion). Mirrored so a citation cannot present a retired record as current.
|
|
26
26
|
*/
|
|
27
|
-
const RETIRED_MEMORY_STATUSES = new Set(['superseded', '
|
|
27
|
+
const RETIRED_MEMORY_STATUSES = new Set(['superseded', 'contradicted', 'stale']);
|
|
28
28
|
/**
|
|
29
29
|
* Parse a stored source ref into what it actually is.
|
|
30
30
|
*
|
package/dist/memory/types.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export type MemoryKind = (typeof MEMORY_KINDS)[number];
|
|
|
29
29
|
export type MemoryKindFilter = MemoryKind | [MemoryKind, ...MemoryKind[]];
|
|
30
30
|
export declare const MEMORY_STATUSES: readonly ["active", "superseded", "contradicted", "stale"];
|
|
31
31
|
export type MemoryStatus = (typeof MEMORY_STATUSES)[number];
|
|
32
|
-
export declare const MEMORY_TRUTH_STATUSES: readonly ["active", "superseded", "contradicted", "stale"
|
|
32
|
+
export declare const MEMORY_TRUTH_STATUSES: readonly ["active", "superseded", "contradicted", "stale"];
|
|
33
33
|
export type MemoryTruthStatus = (typeof MEMORY_TRUTH_STATUSES)[number];
|
|
34
34
|
export declare const MEMORY_EDGE_TYPES: readonly ["supersedes", "builds_on", "synthesizes", "contradicts"];
|
|
35
35
|
export type MemoryEdgeType = (typeof MEMORY_EDGE_TYPES)[number];
|
package/dist/memory/types.js
CHANGED
|
@@ -35,13 +35,7 @@ exports.MEMORY_KINDS = [
|
|
|
35
35
|
'workflow',
|
|
36
36
|
];
|
|
37
37
|
exports.MEMORY_STATUSES = ['active', 'superseded', 'contradicted', 'stale'];
|
|
38
|
-
exports.MEMORY_TRUTH_STATUSES = [
|
|
39
|
-
'active',
|
|
40
|
-
'superseded',
|
|
41
|
-
'contradicted',
|
|
42
|
-
'stale',
|
|
43
|
-
'quarantined',
|
|
44
|
-
];
|
|
38
|
+
exports.MEMORY_TRUTH_STATUSES = ['active', 'superseded', 'contradicted', 'stale'];
|
|
45
39
|
exports.MEMORY_EDGE_TYPES = ['supersedes', 'builds_on', 'synthesizes', 'contradicts'];
|
|
46
40
|
exports.MEMORY_AGENT_ACTIONS = [
|
|
47
41
|
'save',
|