@jungjaehoon/mama-core 1.4.2 → 1.6.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 +48 -10
- package/db/migrations/026-create-canonical-entity-tables.sql +99 -0
- package/db/migrations/027-create-entity-review-support.sql +44 -0
- package/db/migrations/028-create-entity-audit-tables.sql +45 -0
- package/db/migrations/029-extend-entity-observations-observation-type.sql +60 -0
- package/db/migrations/030-case-first-memory-substrate.sql +901 -0
- package/db/migrations/031-wiki-page-index-provenance-columns.sql +2 -0
- package/db/migrations/032-add-memory-provenance-columns.sql +21 -0
- package/db/migrations/033-create-model-runs-and-tool-traces.sql +53 -0
- package/db/migrations/034-add-connector-event-scope-columns.sql +14 -0
- package/db/migrations/035-create-twin-edges.sql +63 -0
- package/db/migrations/036-create-agent-situation-packets.sql +61 -0
- package/dist/agent-graph/alias-write.d.ts +3 -0
- package/dist/agent-graph/alias-write.js +231 -0
- package/dist/agent-graph/entity-resolve.d.ts +3 -0
- package/dist/agent-graph/entity-resolve.js +275 -0
- package/dist/agent-graph/errors.d.ts +4 -0
- package/dist/agent-graph/errors.js +11 -0
- package/dist/agent-graph/graph-query.d.ts +5 -0
- package/dist/agent-graph/graph-query.js +359 -0
- package/dist/agent-graph/index.d.ts +6 -0
- package/dist/agent-graph/index.js +22 -0
- package/dist/agent-graph/types.d.ts +162 -0
- package/dist/agent-graph/types.js +3 -0
- package/dist/agent-situation/builder.d.ts +8 -0
- package/dist/agent-situation/builder.js +239 -0
- package/dist/agent-situation/cache-key.d.ts +4 -0
- package/dist/agent-situation/cache-key.js +64 -0
- package/dist/agent-situation/index.d.ts +7 -0
- package/dist/agent-situation/index.js +28 -0
- package/dist/agent-situation/packet-store.d.ts +27 -0
- package/dist/agent-situation/packet-store.js +228 -0
- package/dist/agent-situation/ranking-policy.d.ts +18 -0
- package/dist/agent-situation/ranking-policy.js +75 -0
- package/dist/agent-situation/source-readers.d.ts +52 -0
- package/dist/agent-situation/source-readers.js +300 -0
- package/dist/agent-situation/types.d.ts +195 -0
- package/dist/agent-situation/types.js +3 -0
- package/dist/canonicalize.d.ts +38 -0
- package/dist/canonicalize.js +106 -0
- package/dist/cases/case-links.d.ts +116 -0
- package/dist/cases/case-links.js +794 -0
- package/dist/cases/composition-overrides.d.ts +90 -0
- package/dist/cases/composition-overrides.js +724 -0
- package/dist/cases/corrections.d.ts +156 -0
- package/dist/cases/corrections.js +1045 -0
- package/dist/cases/freshness.d.ts +57 -0
- package/dist/cases/freshness.js +283 -0
- package/dist/cases/live-state.d.ts +48 -0
- package/dist/cases/live-state.js +256 -0
- package/dist/cases/membership-explain.d.ts +56 -0
- package/dist/cases/membership-explain.js +140 -0
- package/dist/cases/membership-matcher.d.ts +23 -0
- package/dist/cases/membership-matcher.js +193 -0
- package/dist/cases/merge-split.d.ts +61 -0
- package/dist/cases/merge-split.js +368 -0
- package/dist/cases/role-inference.d.ts +10 -0
- package/dist/cases/role-inference.js +85 -0
- package/dist/cases/search-rollup.d.ts +27 -0
- package/dist/cases/search-rollup.js +309 -0
- package/dist/cases/sqlite-transaction.d.ts +10 -0
- package/dist/cases/sqlite-transaction.js +62 -0
- package/dist/cases/store.d.ts +74 -0
- package/dist/cases/store.js +816 -0
- package/dist/cases/target-ref.d.ts +25 -0
- package/dist/cases/target-ref.js +22 -0
- package/dist/cases/timeline-range.d.ts +6 -0
- package/dist/cases/timeline-range.js +322 -0
- package/dist/cases/tombstone-sweeper.d.ts +13 -0
- package/dist/cases/tombstone-sweeper.js +128 -0
- package/dist/cases/types.d.ts +244 -0
- package/dist/cases/types.js +47 -0
- package/dist/cases/wiki-page-index.d.ts +50 -0
- package/dist/cases/wiki-page-index.js +350 -0
- package/dist/connectors/event-index.d.ts +45 -0
- package/dist/connectors/event-index.js +381 -0
- package/dist/connectors/raw-query.d.ts +18 -0
- package/dist/connectors/raw-query.js +305 -0
- package/dist/connectors/types.d.ts +109 -0
- package/dist/connectors/types.js +3 -0
- package/dist/db-adapter/node-sqlite-adapter.d.ts +6 -0
- package/dist/db-adapter/node-sqlite-adapter.js +131 -0
- package/dist/db-manager.d.ts +12 -1
- package/dist/db-manager.js +60 -5
- package/dist/decision-formatter.d.ts +2 -0
- package/dist/decision-formatter.js +11 -8
- package/dist/edges/ref-validation.d.ts +8 -0
- package/dist/edges/ref-validation.js +262 -0
- package/dist/edges/store.d.ts +10 -0
- package/dist/edges/store.js +343 -0
- package/dist/edges/types.d.ts +86 -0
- package/dist/edges/types.js +18 -0
- package/dist/embedding-server/mobile/daemon.d.ts +1 -0
- package/dist/embedding-server/mobile/daemon.js +11 -1
- package/dist/embeddings.js +13 -0
- package/dist/entities/audit-metrics.d.ts +73 -0
- package/dist/entities/audit-metrics.js +128 -0
- package/dist/entities/candidate-generator.d.ts +9 -0
- package/dist/entities/candidate-generator.js +436 -0
- package/dist/entities/entity-impact.d.ts +41 -0
- package/dist/entities/entity-impact.js +140 -0
- package/dist/entities/entity-linked-decision-counts.d.ts +2 -0
- package/dist/entities/entity-linked-decision-counts.js +29 -0
- package/dist/entities/entity-list.d.ts +23 -0
- package/dist/entities/entity-list.js +99 -0
- package/dist/entities/entity-orphan-list.d.ts +26 -0
- package/dist/entities/entity-orphan-list.js +91 -0
- package/dist/entities/entity-search.d.ts +21 -0
- package/dist/entities/entity-search.js +150 -0
- package/dist/entities/errors.d.ts +65 -0
- package/dist/entities/errors.js +124 -0
- package/dist/entities/exact-merge-backfill.d.ts +11 -0
- package/dist/entities/exact-merge-backfill.js +161 -0
- package/dist/entities/lineage-backfill.d.ts +12 -0
- package/dist/entities/lineage-backfill.js +101 -0
- package/dist/entities/lineage-store.d.ts +51 -0
- package/dist/entities/lineage-store.js +308 -0
- package/dist/entities/normalization.d.ts +14 -0
- package/dist/entities/normalization.js +63 -0
- package/dist/entities/policy-store.d.ts +17 -0
- package/dist/entities/policy-store.js +263 -0
- package/dist/entities/policy-types.d.ts +72 -0
- package/dist/entities/policy-types.js +59 -0
- package/dist/entities/projection.d.ts +8 -0
- package/dist/entities/projection.js +82 -0
- package/dist/entities/provenance-query.d.ts +33 -0
- package/dist/entities/provenance-query.js +167 -0
- package/dist/entities/read-identity.d.ts +31 -0
- package/dist/entities/read-identity.js +264 -0
- package/dist/entities/recall-bridge.d.ts +5 -0
- package/dist/entities/recall-bridge.js +171 -0
- package/dist/entities/resolution-engine.d.ts +15 -0
- package/dist/entities/resolution-engine.js +69 -0
- package/dist/entities/rollback-preview.d.ts +39 -0
- package/dist/entities/rollback-preview.js +235 -0
- package/dist/entities/source-locator.d.ts +3 -0
- package/dist/entities/source-locator.js +32 -0
- package/dist/entities/store.d.ts +75 -0
- package/dist/entities/store.js +465 -0
- package/dist/entities/types.d.ts +162 -0
- package/dist/entities/types.js +30 -0
- package/dist/index.d.ts +62 -3
- package/dist/index.js +116 -26
- package/dist/mama-api.d.ts +53 -35
- package/dist/mama-api.js +437 -78
- package/dist/memory/api.d.ts +26 -38
- package/dist/memory/api.js +772 -68
- package/dist/memory/event-store.d.ts +3 -0
- package/dist/memory/event-store.js +21 -2
- package/dist/memory/provenance-audit.d.ts +22 -0
- package/dist/memory/provenance-audit.js +112 -0
- package/dist/memory/provenance-query.d.ts +11 -0
- package/dist/memory/provenance-query.js +193 -0
- package/dist/memory/provenance.d.ts +29 -0
- package/dist/memory/provenance.js +136 -0
- package/dist/memory/scope-backfill.d.ts +17 -0
- package/dist/memory/scope-backfill.js +77 -0
- package/dist/memory/types.d.ts +97 -16
- package/dist/model-runs/store.d.ts +13 -0
- package/dist/model-runs/store.js +457 -0
- package/dist/model-runs/tool-trace-store.d.ts +4 -0
- package/dist/model-runs/tool-trace-store.js +114 -0
- package/dist/model-runs/types.d.ts +69 -0
- package/dist/model-runs/types.js +5 -0
- package/dist/runtime/trusted-provenance.d.ts +3 -0
- package/dist/runtime/trusted-provenance.js +6 -0
- package/dist/search/feedback-store.d.ts +59 -0
- package/dist/search/feedback-store.js +211 -0
- package/dist/search/question-type.d.ts +5 -0
- package/dist/search/question-type.js +41 -0
- package/dist/search/ranker-features.d.ts +23 -0
- package/dist/search/ranker-features.js +104 -0
- package/dist/search/ranker-rescore.d.ts +31 -0
- package/dist/search/ranker-rescore.js +226 -0
- package/dist/search/ranker-trainer.d.ts +94 -0
- package/dist/search/ranker-trainer.js +860 -0
- package/dist/search/search-quality.d.ts +36 -0
- package/dist/search/search-quality.js +29 -0
- package/dist/test-utils.d.ts +14 -0
- package/dist/test-utils.js +52 -0
- package/package.json +28 -3
package/dist/mama-api.js
CHANGED
|
@@ -22,8 +22,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.listRecentMemoryEvents = exports.listOpenAuditFindings = exports.getChannelSummary = exports.upsertChannelSummary = exports.recordMemoryAudit = exports.createAuditAck = exports.buildMemoryBootstrap = exports.evolveMemory = exports.ingestMemory = exports.buildProfile = exports.recallMemory = exports.saveMemory = void 0;
|
|
25
|
+
exports.listToolTracesForRun = exports.appendToolTrace = exports.getModelRunInAdapter = exports.getModelRun = exports.failModelRunInAdapter = exports.failModelRun = exports.commitModelRunInAdapter = exports.commitModelRun = exports.beginModelRunInAdapter = exports.beginModelRun = exports.listRecentMemoryEvents = exports.listMemoryEventsForMemory = exports.listMemoriesByModelRunId = exports.listMemoriesByGatewayCallId = exports.listMemoriesByEnvelopeHash = exports.getMemoryProvenance = exports.listOpenAuditFindings = exports.getChannelSummary = exports.upsertChannelSummary = exports.recordMemoryAudit = exports.createAuditAck = exports.buildMemoryBootstrap = exports.evolveMemory = exports.ingestConversationWithTrustedProvenance = exports.ingestConversation = exports.ingestWithTrustedProvenance = exports.ingestMemory = exports.buildProfile = exports.recallMemory = exports.saveMemoryWithTrustedProvenance = exports.saveMemory = void 0;
|
|
26
26
|
exports.save = save;
|
|
27
|
+
exports.saveWithTrustedProvenance = saveWithTrustedProvenance;
|
|
27
28
|
exports.suggest = suggest;
|
|
28
29
|
exports.list = listDecisions;
|
|
29
30
|
exports.listCheckpoints = listCheckpoints;
|
|
@@ -50,6 +51,7 @@ exports.restoreLinkBackup = restoreLinkBackup;
|
|
|
50
51
|
exports.verifyBackupExists = verifyBackupExists;
|
|
51
52
|
exports.deleteAutoLinks = deleteAutoLinks;
|
|
52
53
|
exports.validateCleanupResult = validateCleanupResult;
|
|
54
|
+
exports.expandWithGraph = expandWithGraph;
|
|
53
55
|
// Node built-ins
|
|
54
56
|
const fs_1 = __importDefault(require("fs"));
|
|
55
57
|
const path_1 = __importDefault(require("path"));
|
|
@@ -67,9 +69,13 @@ const ollama_client_js_1 = require("./ollama-client.js");
|
|
|
67
69
|
const debug_logger_js_1 = require("./debug-logger.js");
|
|
68
70
|
const api_js_1 = require("./memory/api.js");
|
|
69
71
|
Object.defineProperty(exports, "saveMemory", { enumerable: true, get: function () { return api_js_1.saveMemory; } });
|
|
72
|
+
Object.defineProperty(exports, "saveMemoryWithTrustedProvenance", { enumerable: true, get: function () { return api_js_1.saveMemoryWithTrustedProvenance; } });
|
|
70
73
|
Object.defineProperty(exports, "recallMemory", { enumerable: true, get: function () { return api_js_1.recallMemory; } });
|
|
71
74
|
Object.defineProperty(exports, "buildProfile", { enumerable: true, get: function () { return api_js_1.buildProfile; } });
|
|
72
75
|
Object.defineProperty(exports, "ingestMemory", { enumerable: true, get: function () { return api_js_1.ingestMemory; } });
|
|
76
|
+
Object.defineProperty(exports, "ingestWithTrustedProvenance", { enumerable: true, get: function () { return api_js_1.ingestWithTrustedProvenance; } });
|
|
77
|
+
Object.defineProperty(exports, "ingestConversation", { enumerable: true, get: function () { return api_js_1.ingestConversation; } });
|
|
78
|
+
Object.defineProperty(exports, "ingestConversationWithTrustedProvenance", { enumerable: true, get: function () { return api_js_1.ingestConversationWithTrustedProvenance; } });
|
|
73
79
|
Object.defineProperty(exports, "evolveMemory", { enumerable: true, get: function () { return api_js_1.evolveMemory; } });
|
|
74
80
|
Object.defineProperty(exports, "buildMemoryBootstrap", { enumerable: true, get: function () { return api_js_1.buildMemoryBootstrap; } });
|
|
75
81
|
Object.defineProperty(exports, "createAuditAck", { enumerable: true, get: function () { return api_js_1.createAuditAck; } });
|
|
@@ -79,7 +85,29 @@ Object.defineProperty(exports, "getChannelSummary", { enumerable: true, get: fun
|
|
|
79
85
|
const finding_store_js_1 = require("./memory/finding-store.js");
|
|
80
86
|
Object.defineProperty(exports, "listOpenAuditFindings", { enumerable: true, get: function () { return finding_store_js_1.listOpenAuditFindings; } });
|
|
81
87
|
const event_store_js_1 = require("./memory/event-store.js");
|
|
88
|
+
Object.defineProperty(exports, "listMemoryEventsForMemory", { enumerable: true, get: function () { return event_store_js_1.listMemoryEventsForMemory; } });
|
|
82
89
|
Object.defineProperty(exports, "listRecentMemoryEvents", { enumerable: true, get: function () { return event_store_js_1.listRecentMemoryEvents; } });
|
|
90
|
+
const provenance_query_js_1 = require("./memory/provenance-query.js");
|
|
91
|
+
Object.defineProperty(exports, "getMemoryProvenance", { enumerable: true, get: function () { return provenance_query_js_1.getMemoryProvenance; } });
|
|
92
|
+
Object.defineProperty(exports, "listMemoriesByEnvelopeHash", { enumerable: true, get: function () { return provenance_query_js_1.listMemoriesByEnvelopeHash; } });
|
|
93
|
+
Object.defineProperty(exports, "listMemoriesByGatewayCallId", { enumerable: true, get: function () { return provenance_query_js_1.listMemoriesByGatewayCallId; } });
|
|
94
|
+
Object.defineProperty(exports, "listMemoriesByModelRunId", { enumerable: true, get: function () { return provenance_query_js_1.listMemoriesByModelRunId; } });
|
|
95
|
+
const store_js_1 = require("./model-runs/store.js");
|
|
96
|
+
Object.defineProperty(exports, "beginModelRun", { enumerable: true, get: function () { return store_js_1.beginModelRun; } });
|
|
97
|
+
Object.defineProperty(exports, "beginModelRunInAdapter", { enumerable: true, get: function () { return store_js_1.beginModelRunInAdapter; } });
|
|
98
|
+
Object.defineProperty(exports, "commitModelRun", { enumerable: true, get: function () { return store_js_1.commitModelRun; } });
|
|
99
|
+
Object.defineProperty(exports, "commitModelRunInAdapter", { enumerable: true, get: function () { return store_js_1.commitModelRunInAdapter; } });
|
|
100
|
+
Object.defineProperty(exports, "failModelRun", { enumerable: true, get: function () { return store_js_1.failModelRun; } });
|
|
101
|
+
Object.defineProperty(exports, "failModelRunInAdapter", { enumerable: true, get: function () { return store_js_1.failModelRunInAdapter; } });
|
|
102
|
+
Object.defineProperty(exports, "getModelRun", { enumerable: true, get: function () { return store_js_1.getModelRun; } });
|
|
103
|
+
Object.defineProperty(exports, "getModelRunInAdapter", { enumerable: true, get: function () { return store_js_1.getModelRunInAdapter; } });
|
|
104
|
+
const tool_trace_store_js_1 = require("./model-runs/tool-trace-store.js");
|
|
105
|
+
Object.defineProperty(exports, "appendToolTrace", { enumerable: true, get: function () { return tool_trace_store_js_1.appendToolTrace; } });
|
|
106
|
+
Object.defineProperty(exports, "listToolTracesForRun", { enumerable: true, get: function () { return tool_trace_store_js_1.listToolTracesForRun; } });
|
|
107
|
+
const search_rollup_js_1 = require("./cases/search-rollup.js");
|
|
108
|
+
const ranker_rescore_js_1 = require("./search/ranker-rescore.js");
|
|
109
|
+
const ranker_features_js_1 = require("./search/ranker-features.js");
|
|
110
|
+
const search_quality_js_1 = require("./search/search-quality.js");
|
|
83
111
|
// Session-level warning cooldown cache (Story 1.1, 1.2)
|
|
84
112
|
// Prevents spam by tracking warned topics per session
|
|
85
113
|
const warnedTopicsCache = new Map();
|
|
@@ -111,7 +139,7 @@ const WARNING_COOLDOWN_MS = 5 * 60 * 1000; // 5 minutes
|
|
|
111
139
|
* outcome: 'success'
|
|
112
140
|
* });
|
|
113
141
|
*/
|
|
114
|
-
async function
|
|
142
|
+
async function saveInternal({ topic, decision, reasoning, confidence = 0.5, type = 'user_decision', outcome = 'pending', failure_reason = null, limitation = null, trust_context: _trust_context = null, is_static, scopes: inputScopes, event_date, timelineEvent, }, options) {
|
|
115
143
|
// Validate required fields
|
|
116
144
|
if (!topic || typeof topic !== 'string') {
|
|
117
145
|
throw new Error('mama.save() requires topic (string)');
|
|
@@ -161,19 +189,35 @@ async function save({ topic, decision, reasoning, confidence = 0.5, type = 'user
|
|
|
161
189
|
// Future: Will use decision_type column for proper distinction
|
|
162
190
|
const _userInvolvement = type === 'user_decision' ? 'approved' : null;
|
|
163
191
|
(0, progress_indicator_js_1.logProgress)(`Saving decision: ${topic.substring(0, 30)}...`);
|
|
164
|
-
const { id: decisionId
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
192
|
+
const { id: decisionId, timeline_event_id: timelineEventId, timeline_event_ids: timelineEventIds, } = options
|
|
193
|
+
? await (0, api_js_1.saveMemoryWithTrustedProvenance)({
|
|
194
|
+
topic,
|
|
195
|
+
kind: is_static === 1 ? 'preference' : 'decision',
|
|
196
|
+
summary: decision,
|
|
197
|
+
details: reasoning,
|
|
198
|
+
confidence,
|
|
199
|
+
scopes: Array.isArray(inputScopes) && inputScopes.length > 0 ? inputScopes : [],
|
|
200
|
+
source: {
|
|
201
|
+
package: 'mama-core',
|
|
202
|
+
source_type: 'legacy_save',
|
|
203
|
+
},
|
|
204
|
+
eventDate: event_date ?? undefined,
|
|
205
|
+
timelineEvent,
|
|
206
|
+
}, options)
|
|
207
|
+
: await (0, api_js_1.saveMemory)({
|
|
208
|
+
topic,
|
|
209
|
+
kind: is_static === 1 ? 'preference' : 'decision',
|
|
210
|
+
summary: decision,
|
|
211
|
+
details: reasoning,
|
|
212
|
+
confidence,
|
|
213
|
+
scopes: Array.isArray(inputScopes) && inputScopes.length > 0 ? inputScopes : [],
|
|
214
|
+
source: {
|
|
215
|
+
package: 'mama-core',
|
|
216
|
+
source_type: 'legacy_save',
|
|
217
|
+
},
|
|
218
|
+
eventDate: event_date ?? undefined,
|
|
219
|
+
timelineEvent,
|
|
220
|
+
});
|
|
177
221
|
(0, progress_indicator_js_1.logComplete)(`Decision saved: ${decisionId.substring(0, 20)}...`);
|
|
178
222
|
// Update user_involvement, outcome, failure_reason, limitation
|
|
179
223
|
// Note: learnDecision always sets 'requested', we need to override it
|
|
@@ -255,13 +299,17 @@ async function save({ topic, decision, reasoning, confidence = 0.5, type = 'user
|
|
|
255
299
|
if (searchResults && typeof searchResults === 'object' && 'results' in searchResults) {
|
|
256
300
|
// Filter out the decision we just saved
|
|
257
301
|
similar_decisions = searchResults.results
|
|
302
|
+
.filter((d) => d.source_type === 'decision')
|
|
258
303
|
.filter((d) => d.id !== decisionId)
|
|
259
304
|
.map((d) => ({
|
|
260
305
|
id: d.id,
|
|
261
306
|
topic: d.topic,
|
|
262
307
|
decision: d.decision,
|
|
263
308
|
similarity: d.similarity,
|
|
309
|
+
retrieval_score: d.retrieval_score ?? null,
|
|
264
310
|
created_at: d.created_at,
|
|
311
|
+
event_date: d.event_date ?? null,
|
|
312
|
+
event_datetime: d.event_datetime ?? null,
|
|
265
313
|
}));
|
|
266
314
|
if (similar_decisions.length > 0) {
|
|
267
315
|
(0, progress_indicator_js_1.logComplete)(`Found ${similar_decisions.length} related decision(s)`);
|
|
@@ -308,6 +356,9 @@ async function save({ topic, decision, reasoning, confidence = 0.5, type = 'user
|
|
|
308
356
|
return {
|
|
309
357
|
success: true,
|
|
310
358
|
id: decisionId,
|
|
359
|
+
saved_decision_id: decisionId,
|
|
360
|
+
timeline_event_id: timelineEventId ?? null,
|
|
361
|
+
timeline_event_ids: timelineEventIds ?? [],
|
|
311
362
|
...(similar_decisions.length > 0 && { similar_decisions }),
|
|
312
363
|
...(warning && { warning }),
|
|
313
364
|
...(collaboration_hint && { collaboration_hint }),
|
|
@@ -698,62 +749,327 @@ function applyRecencyBoost(results, options = {}) {
|
|
|
698
749
|
})
|
|
699
750
|
.sort((a, b) => (b.final_score ?? 0) - (a.final_score ?? 0));
|
|
700
751
|
}
|
|
752
|
+
/** Phase 3 Task 33: learned-ranker meta attached to mama.suggest response. */
|
|
753
|
+
function buildRankerMeta(applied, modelId, skippedReason) {
|
|
754
|
+
const meta = {
|
|
755
|
+
model_id: modelId,
|
|
756
|
+
feature_set_version: ranker_features_js_1.SEARCH_RANKER_FEATURE_SET_VERSION,
|
|
757
|
+
applied,
|
|
758
|
+
mode: 'offline',
|
|
759
|
+
};
|
|
760
|
+
if (skippedReason) {
|
|
761
|
+
meta.skipped_reason = skippedReason;
|
|
762
|
+
}
|
|
763
|
+
return meta;
|
|
764
|
+
}
|
|
765
|
+
function resultRecord(result) {
|
|
766
|
+
if (typeof result.record === 'object' &&
|
|
767
|
+
result.record !== null &&
|
|
768
|
+
!Array.isArray(result.record)) {
|
|
769
|
+
return result.record;
|
|
770
|
+
}
|
|
771
|
+
return {};
|
|
772
|
+
}
|
|
773
|
+
function stringOrNull(value) {
|
|
774
|
+
if (value === null || value === undefined) {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
return String(value);
|
|
778
|
+
}
|
|
779
|
+
function numberOrNull(value) {
|
|
780
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
return value;
|
|
784
|
+
}
|
|
785
|
+
function confidenceValue(record, fallback) {
|
|
786
|
+
const numeric = numberOrNull(record.confidence);
|
|
787
|
+
if (numeric !== null) {
|
|
788
|
+
return numeric;
|
|
789
|
+
}
|
|
790
|
+
switch (record.confidence) {
|
|
791
|
+
case 'high':
|
|
792
|
+
return 0.9;
|
|
793
|
+
case 'medium':
|
|
794
|
+
return 0.6;
|
|
795
|
+
case 'low':
|
|
796
|
+
return 0.3;
|
|
797
|
+
default:
|
|
798
|
+
return fallback;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
function mapRolledUpResult(result) {
|
|
802
|
+
const record = resultRecord(result);
|
|
803
|
+
const retrievalDiagnostics = result.retrieval_diagnostics;
|
|
804
|
+
const topic = stringOrNull(record.topic ?? record.title) ?? result.source_id;
|
|
805
|
+
// For wiki_page leaves, prefer the markdown body (`content`) in `decision` so
|
|
806
|
+
// downstream consumers see the meaningful body rather than the short title.
|
|
807
|
+
// Decision/checkpoint records use their own fields (summary/decision).
|
|
808
|
+
const isWikiPageLeaf = result.source_type === 'wiki_page';
|
|
809
|
+
const decision = isWikiPageLeaf
|
|
810
|
+
? (stringOrNull(record.content ?? record.summary ?? record.decision ?? record.title) ??
|
|
811
|
+
result.source_id)
|
|
812
|
+
: (stringOrNull(record.summary ?? record.decision ?? record.title ?? record.content) ??
|
|
813
|
+
result.source_id);
|
|
814
|
+
const reasoning = stringOrNull(record.details ?? record.reasoning ?? record.status_reason ?? record.content) ??
|
|
815
|
+
'';
|
|
816
|
+
return {
|
|
817
|
+
id: result.source_id,
|
|
818
|
+
topic,
|
|
819
|
+
decision,
|
|
820
|
+
reasoning,
|
|
821
|
+
confidence: confidenceValue(record, result.score),
|
|
822
|
+
// Back-compat with pre-rollup consumers (swarm-mama-adapter tests,
|
|
823
|
+
// older callers): similarity mirrors the retrieval score when we don't
|
|
824
|
+
// have a separate similarity measure. retrieval_score remains the
|
|
825
|
+
// authoritative field for Phase 3 code paths.
|
|
826
|
+
similarity: result.score,
|
|
827
|
+
retrieval_score: result.score,
|
|
828
|
+
created_at: record.created_at ?? null,
|
|
829
|
+
event_date: record.event_date ?? null,
|
|
830
|
+
event_datetime: record.event_datetime ?? null,
|
|
831
|
+
graph_source: retrievalDiagnostics?.graph_source ?? 'primary',
|
|
832
|
+
graph_rank: 1,
|
|
833
|
+
related_to: null,
|
|
834
|
+
edge_reason: null,
|
|
835
|
+
case_id: result.case_id,
|
|
836
|
+
source_type: result.source_type,
|
|
837
|
+
contributing_leaves: result.contributing_leaves ?? null,
|
|
838
|
+
...(result.contributing_leaf_diagnostics
|
|
839
|
+
? { contributing_leaf_diagnostics: result.contributing_leaf_diagnostics }
|
|
840
|
+
: {}),
|
|
841
|
+
...(retrievalDiagnostics ? { retrieval_diagnostics: retrievalDiagnostics } : {}),
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
async function save(params) {
|
|
845
|
+
return saveInternal(params);
|
|
846
|
+
}
|
|
847
|
+
async function saveWithTrustedProvenance(params, options) {
|
|
848
|
+
return saveInternal(params, options);
|
|
849
|
+
}
|
|
701
850
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
702
851
|
async function suggest(userQuestion, options = {}) {
|
|
703
852
|
if (!userQuestion || typeof userQuestion !== 'string') {
|
|
704
853
|
throw new Error('mama.suggest() requires userQuestion (string)');
|
|
705
854
|
}
|
|
706
|
-
const { format = 'json', limit = 5, threshold, useReranking = false,
|
|
855
|
+
const { format = 'json', limit = 5, threshold, useReranking = false, rerankWithLearned = false,
|
|
707
856
|
// Recency boosting parameters (Gaussian Decay - Elasticsearch style)
|
|
708
857
|
recencyWeight = 0.3, // 0-1: How much to weight recency (0.3 = 70% semantic, 30% recency)
|
|
709
858
|
recencyScale = 7, // Days until recency score drops to 50%
|
|
710
859
|
recencyDecay = 0.5, // Score at scale point (0.5 = 50%)
|
|
711
860
|
disableRecency = false, // Set true to disable recency boosting entirely
|
|
712
|
-
|
|
861
|
+
strict, strictness, includeRelated, minLexicalSupport, diagnostics: includeDiagnostics, } = options;
|
|
862
|
+
const normalizedSearchOptions = (0, search_quality_js_1.normalizeSearchQualityOptions)({
|
|
863
|
+
threshold,
|
|
864
|
+
strict,
|
|
865
|
+
strictness,
|
|
866
|
+
disableRecency,
|
|
867
|
+
includeRelated,
|
|
868
|
+
topicPrefix: options.topicPrefix,
|
|
869
|
+
minLexicalSupport,
|
|
870
|
+
diagnostics: includeDiagnostics,
|
|
871
|
+
});
|
|
872
|
+
const memoryV2QualityContractRequested = threshold !== undefined ||
|
|
873
|
+
strict !== undefined ||
|
|
874
|
+
strictness !== undefined ||
|
|
875
|
+
includeRelated !== undefined ||
|
|
876
|
+
minLexicalSupport !== undefined ||
|
|
877
|
+
includeDiagnostics === true ||
|
|
878
|
+
options.topicPrefix !== undefined ||
|
|
879
|
+
options.scopes !== undefined;
|
|
880
|
+
const rerankPoolLimit = rerankWithLearned ? Math.max(limit * 4, limit + 5) : limit;
|
|
713
881
|
try {
|
|
714
882
|
const bundle = await (0, api_js_1.recallMemory)(userQuestion, {
|
|
715
883
|
includeProfile: false,
|
|
716
884
|
topicPrefix: options.topicPrefix,
|
|
885
|
+
limit: rerankPoolLimit,
|
|
886
|
+
threshold,
|
|
887
|
+
strict,
|
|
888
|
+
strictness,
|
|
889
|
+
disableRecency,
|
|
890
|
+
includeRelated,
|
|
891
|
+
minLexicalSupport,
|
|
892
|
+
diagnostics: includeDiagnostics,
|
|
717
893
|
...(options.scopes && { scopes: options.scopes }),
|
|
718
894
|
});
|
|
895
|
+
const diagnosticsByMemoryId = new Map(bundle.memories
|
|
896
|
+
.filter((memory) => memory.retrieval_diagnostics)
|
|
897
|
+
.map((memory) => [memory.id, memory.retrieval_diagnostics]));
|
|
898
|
+
const rawFusedHits = bundle.fused_hits ?? [];
|
|
899
|
+
const fusedHits = rawFusedHits.map((hit) => {
|
|
900
|
+
if (hit.source_type !== 'decision') {
|
|
901
|
+
return hit;
|
|
902
|
+
}
|
|
903
|
+
const recordDiagnostics = typeof hit.record === 'object' && hit.record !== null && !Array.isArray(hit.record)
|
|
904
|
+
? hit.record.retrieval_diagnostics
|
|
905
|
+
: undefined;
|
|
906
|
+
const retrievalDiagnostics = diagnosticsByMemoryId.get(hit.source_id) ?? recordDiagnostics;
|
|
907
|
+
if (!retrievalDiagnostics) {
|
|
908
|
+
return hit;
|
|
909
|
+
}
|
|
910
|
+
const record = typeof hit.record === 'object' && hit.record !== null && !Array.isArray(hit.record)
|
|
911
|
+
? { ...hit.record, retrieval_diagnostics: retrievalDiagnostics }
|
|
912
|
+
: hit.record;
|
|
913
|
+
return {
|
|
914
|
+
...hit,
|
|
915
|
+
record,
|
|
916
|
+
retrieval_diagnostics: retrievalDiagnostics,
|
|
917
|
+
};
|
|
918
|
+
});
|
|
919
|
+
const rolledUp = fusedHits.length > 0 ? (0, search_rollup_js_1.rollUpSearchHits)({ fusedHits, adapter: (0, memory_store_js_1.getAdapter)() }) : [];
|
|
920
|
+
const diagnosticsResponse = includeDiagnostics === true ? { diagnostics: bundle.search_meta.diagnostics ?? null } : {};
|
|
921
|
+
// Phase 3 Task 33: compute base ranker meta once so every return path
|
|
922
|
+
// (rolledUp, memories fallback, vector-search fallback) can attach it.
|
|
923
|
+
// rerankWithLearned-driven rescoring still only applies to result arrays
|
|
924
|
+
// that match the ranker's expected shape (id + source_type + case_id).
|
|
925
|
+
const baseRankerMeta = useReranking
|
|
926
|
+
? buildRankerMeta(false, null, 'llm_reranking_requested')
|
|
927
|
+
: rerankWithLearned
|
|
928
|
+
? null // marker: rescoring requested, actual meta set per-path after rescore
|
|
929
|
+
: buildRankerMeta(false, null, 'feature_disabled');
|
|
930
|
+
const applyLearnedRanker = (results) => {
|
|
931
|
+
if (baseRankerMeta !== null) {
|
|
932
|
+
return { results, meta: baseRankerMeta };
|
|
933
|
+
}
|
|
934
|
+
// Phase 3 Task 33: the caller opted in via rerankWithLearned, but the
|
|
935
|
+
// runtime `search_ranker_enabled` gate still has final say. This lets
|
|
936
|
+
// operators disable the learned ranker globally during rollback without
|
|
937
|
+
// touching any caller code.
|
|
938
|
+
let runtimeEnabled = true;
|
|
939
|
+
try {
|
|
940
|
+
runtimeEnabled = (0, ranker_rescore_js_1.isSearchRankerEnabled)((0, memory_store_js_1.getAdapter)());
|
|
941
|
+
}
|
|
942
|
+
catch (err) {
|
|
943
|
+
(0, debug_logger_js_1.warn)(`[mama.suggest] isSearchRankerEnabled check failed: ${String(err)}`);
|
|
944
|
+
}
|
|
945
|
+
if (!runtimeEnabled) {
|
|
946
|
+
return { results, meta: buildRankerMeta(false, null, 'feature_disabled') };
|
|
947
|
+
}
|
|
948
|
+
try {
|
|
949
|
+
const rescored = (0, ranker_rescore_js_1.rescoreSearchResults)((0, memory_store_js_1.getAdapter)(), {
|
|
950
|
+
query: userQuestion,
|
|
951
|
+
results,
|
|
952
|
+
});
|
|
953
|
+
return {
|
|
954
|
+
results: rescored.results,
|
|
955
|
+
meta: buildRankerMeta(rescored.skipped_reason === undefined, rescored.model_id, rescored.skipped_reason),
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
catch (err) {
|
|
959
|
+
(0, debug_logger_js_1.warn)(`[mama.suggest] learned-ranker rescore failed: ${String(err)}`);
|
|
960
|
+
return { results, meta: buildRankerMeta(false, null, 'rescore_error') };
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
const summarizeGraphExpansion = (rows) => {
|
|
964
|
+
const sources = {
|
|
965
|
+
primary: 0,
|
|
966
|
+
supersedes_chain: 0,
|
|
967
|
+
refines: 0,
|
|
968
|
+
refined_by: 0,
|
|
969
|
+
contradicts: 0,
|
|
970
|
+
};
|
|
971
|
+
let expandedCount = 0;
|
|
972
|
+
for (const row of rows) {
|
|
973
|
+
const graphSource = row.graph_source ?? 'primary';
|
|
974
|
+
if (graphSource === 'primary') {
|
|
975
|
+
sources.primary += 1;
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
expandedCount += 1;
|
|
979
|
+
if (graphSource in sources) {
|
|
980
|
+
const key = graphSource;
|
|
981
|
+
sources[key] += 1;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
return {
|
|
985
|
+
total_results: rows.length,
|
|
986
|
+
primary_count: sources.primary,
|
|
987
|
+
expanded_count: expandedCount,
|
|
988
|
+
sources,
|
|
989
|
+
};
|
|
990
|
+
};
|
|
991
|
+
if (rolledUp.length > 0) {
|
|
992
|
+
const filteredResults = rolledUp.slice(0, rerankPoolLimit);
|
|
993
|
+
const { results: mappedResults, meta: rankerMeta } = applyLearnedRanker(filteredResults.map(mapRolledUpResult));
|
|
994
|
+
const limitedResults = mappedResults.slice(0, limit);
|
|
995
|
+
if (format === 'markdown') {
|
|
996
|
+
const context = limitedResults
|
|
997
|
+
.map((result, index) => `${index + 1}. [${result.topic}] ${result.decision}\n ${result.reasoning}`)
|
|
998
|
+
.join('\n');
|
|
999
|
+
return `🔍 Search method: memory_v2\n${context}`;
|
|
1000
|
+
}
|
|
1001
|
+
return {
|
|
1002
|
+
query: userQuestion,
|
|
1003
|
+
results: limitedResults,
|
|
1004
|
+
...diagnosticsResponse,
|
|
1005
|
+
meta: {
|
|
1006
|
+
count: limitedResults.length,
|
|
1007
|
+
search_method: 'memory_v2',
|
|
1008
|
+
threshold: normalizedSearchOptions.threshold,
|
|
1009
|
+
recency_boost: disableRecency
|
|
1010
|
+
? null
|
|
1011
|
+
: {
|
|
1012
|
+
weight: recencyWeight,
|
|
1013
|
+
scale: recencyScale,
|
|
1014
|
+
decay: recencyDecay,
|
|
1015
|
+
},
|
|
1016
|
+
graph_expansion: summarizeGraphExpansion(limitedResults),
|
|
1017
|
+
ranker: rankerMeta,
|
|
1018
|
+
},
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
719
1021
|
if (bundle.memories.length > 0) {
|
|
720
1022
|
// recallMemory uses RRF fusion — confidence is overwritten with the normalized
|
|
721
1023
|
// retrieval score (0-1 range, where 1.0 = best match in this result set).
|
|
722
1024
|
// The original stored confidence is lost after RRF normalization.
|
|
723
1025
|
// We capture the retrieval score separately so `similarity` reflects search
|
|
724
1026
|
// relevance while `confidence` is passed through as-is from the bundle.
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1027
|
+
const filteredMemories = bundle.memories.slice(0, rerankPoolLimit);
|
|
1028
|
+
const baseRows = filteredMemories.map((memory) => ({
|
|
1029
|
+
id: memory.id,
|
|
1030
|
+
topic: memory.topic,
|
|
1031
|
+
decision: memory.summary,
|
|
1032
|
+
reasoning: memory.details,
|
|
1033
|
+
confidence: memory.confidence,
|
|
1034
|
+
// recallMemory currently normalizes fused retrieval rank into `confidence`.
|
|
1035
|
+
// Keep that value visible as retrieval_score, but do not pretend it is
|
|
1036
|
+
// semantic similarity; save-time warning logic keys off `similarity`.
|
|
1037
|
+
similarity: null,
|
|
1038
|
+
retrieval_score: memory.confidence ?? null,
|
|
1039
|
+
final_score: memory.confidence ?? null,
|
|
1040
|
+
created_at: memory.created_at,
|
|
1041
|
+
event_date: memory.event_date ?? null,
|
|
1042
|
+
event_datetime: memory.event_datetime ?? null,
|
|
1043
|
+
graph_source: memory.retrieval_diagnostics?.graph_source ?? 'primary',
|
|
1044
|
+
graph_rank: 1,
|
|
1045
|
+
related_to: null,
|
|
1046
|
+
edge_reason: null,
|
|
1047
|
+
case_id: null,
|
|
1048
|
+
source_type: memory.kind ??
|
|
1049
|
+
memory.source?.source_type ??
|
|
1050
|
+
memory.source_type ??
|
|
1051
|
+
memory.type ??
|
|
1052
|
+
'decision',
|
|
1053
|
+
...(memory.retrieval_diagnostics
|
|
1054
|
+
? { retrieval_diagnostics: memory.retrieval_diagnostics }
|
|
1055
|
+
: {}),
|
|
1056
|
+
}));
|
|
1057
|
+
const { results: rankedRows, meta: rankerMeta } = applyLearnedRanker(baseRows);
|
|
1058
|
+
const limitedRows = rankedRows.slice(0, limit);
|
|
728
1059
|
if (format === 'markdown') {
|
|
729
|
-
const context =
|
|
730
|
-
.map((
|
|
1060
|
+
const context = limitedRows
|
|
1061
|
+
.map((row, index) => `${index + 1}. [${row.topic}] ${row.decision}\n ${row.reasoning}`)
|
|
731
1062
|
.join('\n');
|
|
732
1063
|
return `🔍 Search method: memory_v2\n${context}`;
|
|
733
1064
|
}
|
|
734
1065
|
return {
|
|
735
1066
|
query: userQuestion,
|
|
736
|
-
results:
|
|
737
|
-
|
|
738
|
-
topic: memory.topic,
|
|
739
|
-
decision: memory.summary,
|
|
740
|
-
reasoning: memory.details,
|
|
741
|
-
confidence: memory.confidence,
|
|
742
|
-
// memory.confidence is the normalized RRF retrieval score (0-1) after
|
|
743
|
-
// recallMemory. Use it as similarity so the field reflects search relevance
|
|
744
|
-
// rather than the original stored trust score.
|
|
745
|
-
similarity: memory.confidence ?? 1 - idx * 0.01,
|
|
746
|
-
created_at: memory.created_at,
|
|
747
|
-
event_date: memory.event_date ?? null,
|
|
748
|
-
graph_source: 'primary',
|
|
749
|
-
graph_rank: 1,
|
|
750
|
-
related_to: null,
|
|
751
|
-
edge_reason: null,
|
|
752
|
-
})),
|
|
1067
|
+
results: limitedRows,
|
|
1068
|
+
...diagnosticsResponse,
|
|
753
1069
|
meta: {
|
|
754
|
-
count:
|
|
1070
|
+
count: limitedRows.length,
|
|
755
1071
|
search_method: 'memory_v2',
|
|
756
|
-
threshold: threshold
|
|
1072
|
+
threshold: normalizedSearchOptions.threshold,
|
|
757
1073
|
recency_boost: disableRecency
|
|
758
1074
|
? null
|
|
759
1075
|
: {
|
|
@@ -761,18 +1077,34 @@ async function suggest(userQuestion, options = {}) {
|
|
|
761
1077
|
scale: recencyScale,
|
|
762
1078
|
decay: recencyDecay,
|
|
763
1079
|
},
|
|
764
|
-
graph_expansion:
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1080
|
+
graph_expansion: summarizeGraphExpansion(limitedRows),
|
|
1081
|
+
ranker: rankerMeta,
|
|
1082
|
+
},
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
if (memoryV2QualityContractRequested) {
|
|
1086
|
+
const emptyRows = [];
|
|
1087
|
+
const { meta: rankerMeta } = applyLearnedRanker(emptyRows);
|
|
1088
|
+
if (format === 'markdown') {
|
|
1089
|
+
return '🔍 Search method: memory_v2\n';
|
|
1090
|
+
}
|
|
1091
|
+
return {
|
|
1092
|
+
query: userQuestion,
|
|
1093
|
+
results: emptyRows,
|
|
1094
|
+
...diagnosticsResponse,
|
|
1095
|
+
meta: {
|
|
1096
|
+
count: 0,
|
|
1097
|
+
search_method: 'memory_v2',
|
|
1098
|
+
threshold: normalizedSearchOptions.threshold,
|
|
1099
|
+
recency_boost: disableRecency
|
|
1100
|
+
? null
|
|
1101
|
+
: {
|
|
1102
|
+
weight: recencyWeight,
|
|
1103
|
+
scale: recencyScale,
|
|
1104
|
+
decay: recencyDecay,
|
|
774
1105
|
},
|
|
775
|
-
|
|
1106
|
+
graph_expansion: summarizeGraphExpansion(emptyRows),
|
|
1107
|
+
ranker: rankerMeta,
|
|
776
1108
|
},
|
|
777
1109
|
};
|
|
778
1110
|
}
|
|
@@ -791,7 +1123,7 @@ async function suggest(userQuestion, options = {}) {
|
|
|
791
1123
|
const wordCount = userQuestion.split(/\s+/).length;
|
|
792
1124
|
const adaptiveThreshold = threshold !== undefined ? threshold : wordCount < 3 ? 0.7 : 0.6;
|
|
793
1125
|
// Vector search
|
|
794
|
-
results = await (0, memory_store_js_1.vectorSearch)(queryEmbedding,
|
|
1126
|
+
results = await (0, memory_store_js_1.vectorSearch)(queryEmbedding, rerankPoolLimit * 2, 0.5); // Get more candidates
|
|
795
1127
|
// Filter by adaptive threshold
|
|
796
1128
|
results = results.filter((r) => r.similarity >= adaptiveThreshold);
|
|
797
1129
|
// Stage 1.4: Temporal boost — detect time-related queries and boost matching results
|
|
@@ -839,7 +1171,7 @@ async function suggest(userQuestion, options = {}) {
|
|
|
839
1171
|
// Stage 1.7: FTS5 hybrid merge (Haiku Memory Layer)
|
|
840
1172
|
{
|
|
841
1173
|
try {
|
|
842
|
-
const ftsResults = await (0, db_manager_js_1.fts5Search)(userQuestion,
|
|
1174
|
+
const ftsResults = await (0, db_manager_js_1.fts5Search)(userQuestion, rerankPoolLimit * 2);
|
|
843
1175
|
if (ftsResults.length > 0) {
|
|
844
1176
|
// Normalize FTS5 ranks (BM25 returns negative values, closer to 0 = better)
|
|
845
1177
|
const maxRank = Math.max(...ftsResults.map((r) => Math.abs(r.rank)));
|
|
@@ -924,7 +1256,7 @@ async function suggest(userQuestion, options = {}) {
|
|
|
924
1256
|
ORDER BY created_at DESC
|
|
925
1257
|
LIMIT ?
|
|
926
1258
|
`);
|
|
927
|
-
const rows = (await stmt.all(...likeParams,
|
|
1259
|
+
const rows = (await stmt.all(...likeParams, rerankPoolLimit));
|
|
928
1260
|
results = rows.map((row) => ({
|
|
929
1261
|
...row,
|
|
930
1262
|
similarity: 0.75, // Assign moderate similarity for keyword matches
|
|
@@ -949,8 +1281,32 @@ async function suggest(userQuestion, options = {}) {
|
|
|
949
1281
|
if (useReranking) {
|
|
950
1282
|
results = await rerankWithLLM(userQuestion, results);
|
|
951
1283
|
}
|
|
952
|
-
|
|
953
|
-
const
|
|
1284
|
+
const rerankCandidateResults = results.slice(0, rerankPoolLimit);
|
|
1285
|
+
const vectorRows = rerankCandidateResults.map((r) => ({
|
|
1286
|
+
id: r.id,
|
|
1287
|
+
topic: r.topic,
|
|
1288
|
+
decision: r.decision,
|
|
1289
|
+
reasoning: r.reasoning,
|
|
1290
|
+
confidence: r.confidence,
|
|
1291
|
+
similarity: r.similarity,
|
|
1292
|
+
created_at: r.created_at,
|
|
1293
|
+
event_date: r.event_date ?? null,
|
|
1294
|
+
event_datetime: r.event_datetime ?? null,
|
|
1295
|
+
// Recency metadata (NEW - Gaussian Decay)
|
|
1296
|
+
recency_score: r.recency_score,
|
|
1297
|
+
recency_age_days: r.recency_age_days,
|
|
1298
|
+
final_score: r.final_score || r.similarity, // Falls back to similarity if no recency
|
|
1299
|
+
retrieval_score: r.similarity ?? null,
|
|
1300
|
+
// Graph metadata (NEW - Phase 1)
|
|
1301
|
+
graph_source: r.graph_source || 'primary',
|
|
1302
|
+
graph_rank: r.graph_rank || 1.0,
|
|
1303
|
+
related_to: r.related_to || null,
|
|
1304
|
+
edge_reason: r.edge_reason || null,
|
|
1305
|
+
case_id: null,
|
|
1306
|
+
source_type: 'decision',
|
|
1307
|
+
}));
|
|
1308
|
+
const { results: rankedVectorRows, meta: rankerMeta } = applyLearnedRanker(vectorRows);
|
|
1309
|
+
const finalResults = rankedVectorRows.slice(0, limit);
|
|
954
1310
|
// Markdown format (for human display)
|
|
955
1311
|
if (format === 'markdown') {
|
|
956
1312
|
const context = (0, decision_formatter_js_1.formatContext)(finalResults, { maxTokens: 500 });
|
|
@@ -976,27 +1332,9 @@ async function suggest(userQuestion, options = {}) {
|
|
|
976
1332
|
contradicts: finalResults.filter((r) => r.graph_source === 'contradicts').length,
|
|
977
1333
|
},
|
|
978
1334
|
};
|
|
979
|
-
// JSON format (default - LLM-first)
|
|
980
1335
|
return {
|
|
981
1336
|
query: userQuestion,
|
|
982
|
-
results: finalResults
|
|
983
|
-
id: r.id,
|
|
984
|
-
topic: r.topic,
|
|
985
|
-
decision: r.decision,
|
|
986
|
-
reasoning: r.reasoning,
|
|
987
|
-
confidence: r.confidence,
|
|
988
|
-
similarity: r.similarity,
|
|
989
|
-
created_at: r.created_at,
|
|
990
|
-
// Recency metadata (NEW - Gaussian Decay)
|
|
991
|
-
recency_score: r.recency_score,
|
|
992
|
-
recency_age_days: r.recency_age_days,
|
|
993
|
-
final_score: r.final_score || r.similarity, // Falls back to similarity if no recency
|
|
994
|
-
// Graph metadata (NEW - Phase 1)
|
|
995
|
-
graph_source: r.graph_source || 'primary',
|
|
996
|
-
graph_rank: r.graph_rank || 1.0,
|
|
997
|
-
related_to: r.related_to || null,
|
|
998
|
-
edge_reason: r.edge_reason || null,
|
|
999
|
-
})),
|
|
1337
|
+
results: finalResults,
|
|
1000
1338
|
meta: {
|
|
1001
1339
|
count: finalResults.length,
|
|
1002
1340
|
search_method: searchMethod,
|
|
@@ -1011,6 +1349,7 @@ async function suggest(userQuestion, options = {}) {
|
|
|
1011
1349
|
},
|
|
1012
1350
|
// Graph expansion stats (NEW - Phase 1)
|
|
1013
1351
|
graph_expansion: searchMethod.includes('graph') ? graphStats : null,
|
|
1352
|
+
ranker: rankerMeta,
|
|
1014
1353
|
},
|
|
1015
1354
|
};
|
|
1016
1355
|
}
|
|
@@ -1068,7 +1407,7 @@ async function listDecisions(options = {}) {
|
|
|
1068
1407
|
JOIN memory_scope_bindings msb ON msb.memory_id = d.id
|
|
1069
1408
|
WHERE msb.scope_id IN (${placeholders})
|
|
1070
1409
|
AND d.superseded_by IS NULL
|
|
1071
|
-
ORDER BY d.created_at DESC
|
|
1410
|
+
ORDER BY COALESCE(d.event_datetime, d.created_at) DESC, d.created_at DESC
|
|
1072
1411
|
LIMIT ?
|
|
1073
1412
|
`);
|
|
1074
1413
|
decisions = await stmt.all(...scopeIds, limit);
|
|
@@ -1077,7 +1416,7 @@ async function listDecisions(options = {}) {
|
|
|
1077
1416
|
const stmt = adapter.prepare(`
|
|
1078
1417
|
SELECT * FROM decisions
|
|
1079
1418
|
WHERE superseded_by IS NULL
|
|
1080
|
-
ORDER BY created_at DESC
|
|
1419
|
+
ORDER BY COALESCE(event_datetime, created_at) DESC, created_at DESC
|
|
1081
1420
|
LIMIT ?
|
|
1082
1421
|
`);
|
|
1083
1422
|
decisions = await stmt.all(limit);
|
|
@@ -2359,14 +2698,19 @@ function formatQualityReportMarkdown(report) {
|
|
|
2359
2698
|
const mama = {
|
|
2360
2699
|
// Core functions (used by 4 MCP tools)
|
|
2361
2700
|
save,
|
|
2701
|
+
saveWithTrustedProvenance,
|
|
2362
2702
|
suggest,
|
|
2363
2703
|
saveMemory: api_js_1.saveMemory,
|
|
2704
|
+
saveMemoryWithTrustedProvenance: api_js_1.saveMemoryWithTrustedProvenance,
|
|
2364
2705
|
recallMemory: api_js_1.recallMemory,
|
|
2365
2706
|
list: listDecisions,
|
|
2366
2707
|
listCheckpoints,
|
|
2367
2708
|
updateOutcome,
|
|
2368
2709
|
buildProfile: api_js_1.buildProfile,
|
|
2369
2710
|
ingestMemory: api_js_1.ingestMemory,
|
|
2711
|
+
ingestWithTrustedProvenance: api_js_1.ingestWithTrustedProvenance,
|
|
2712
|
+
ingestConversation: api_js_1.ingestConversation,
|
|
2713
|
+
ingestConversationWithTrustedProvenance: api_js_1.ingestConversationWithTrustedProvenance,
|
|
2370
2714
|
evolveMemory: api_js_1.evolveMemory,
|
|
2371
2715
|
buildMemoryBootstrap: api_js_1.buildMemoryBootstrap,
|
|
2372
2716
|
createAuditAck: api_js_1.createAuditAck,
|
|
@@ -2374,7 +2718,22 @@ const mama = {
|
|
|
2374
2718
|
upsertChannelSummary: api_js_1.upsertChannelSummary,
|
|
2375
2719
|
getChannelSummary: api_js_1.getChannelSummary,
|
|
2376
2720
|
listAuditFindings: finding_store_js_1.listOpenAuditFindings,
|
|
2721
|
+
getMemoryProvenance: provenance_query_js_1.getMemoryProvenance,
|
|
2722
|
+
listMemoriesByEnvelopeHash: provenance_query_js_1.listMemoriesByEnvelopeHash,
|
|
2723
|
+
listMemoriesByGatewayCallId: provenance_query_js_1.listMemoriesByGatewayCallId,
|
|
2724
|
+
listMemoriesByModelRunId: provenance_query_js_1.listMemoriesByModelRunId,
|
|
2725
|
+
listMemoryEventsForMemory: event_store_js_1.listMemoryEventsForMemory,
|
|
2377
2726
|
listRecentMemoryEvents: event_store_js_1.listRecentMemoryEvents,
|
|
2727
|
+
beginModelRun: store_js_1.beginModelRun,
|
|
2728
|
+
beginModelRunInAdapter: store_js_1.beginModelRunInAdapter,
|
|
2729
|
+
commitModelRun: store_js_1.commitModelRun,
|
|
2730
|
+
commitModelRunInAdapter: store_js_1.commitModelRunInAdapter,
|
|
2731
|
+
failModelRun: store_js_1.failModelRun,
|
|
2732
|
+
failModelRunInAdapter: store_js_1.failModelRunInAdapter,
|
|
2733
|
+
getModelRun: store_js_1.getModelRun,
|
|
2734
|
+
getModelRunInAdapter: store_js_1.getModelRunInAdapter,
|
|
2735
|
+
appendToolTrace: tool_trace_store_js_1.appendToolTrace,
|
|
2736
|
+
listToolTracesForRun: tool_trace_store_js_1.listToolTracesForRun,
|
|
2378
2737
|
saveCheckpoint,
|
|
2379
2738
|
loadCheckpoint,
|
|
2380
2739
|
// Legacy functions (retained for internal use, not exposed via MCP)
|