@jungjaehoon/mama-core 1.9.0 → 2.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/db/migrations/043-add-tool-trace-failure-code.sql +11 -0
- package/dist/agent-graph/alias-write.js +3 -0
- package/dist/agent-graph/entity-resolve.js +3 -7
- package/dist/agent-graph/graph-query.js +5 -4
- package/dist/agent-graph/types.d.ts +30 -0
- package/dist/cases/store.d.ts +0 -4
- package/dist/cases/store.js +0 -66
- package/dist/cases/wiki-page-index.d.ts +0 -13
- package/dist/cases/wiki-page-index.js +0 -153
- package/dist/connectors/event-index.d.ts +1 -22
- package/dist/connectors/event-index.js +0 -157
- package/dist/context-compile/channel-grant.d.ts +46 -0
- package/dist/context-compile/channel-grant.js +66 -0
- package/dist/context-compile/compiler.js +5 -2
- package/dist/context-compile/index.d.ts +1 -0
- package/dist/context-compile/index.js +1 -0
- package/dist/context-compile/packet-store.d.ts +0 -1
- package/dist/context-compile/packet-store.js +0 -16
- package/dist/context-compile/source-readers.d.ts +1 -0
- package/dist/context-compile/source-readers.js +156 -23
- package/dist/context-compile/types.d.ts +17 -0
- package/dist/context-compile/visibility.js +28 -4
- package/dist/db-adapter/node-sqlite-adapter.js +4 -0
- package/dist/db-manager.d.ts +0 -13
- package/dist/db-manager.js +0 -66
- package/dist/decision-formatter.d.ts +0 -11
- package/dist/decision-formatter.js +0 -122
- package/dist/decision-tracker.d.ts +0 -12
- package/dist/decision-tracker.js +0 -50
- package/dist/edges/ref-validation.d.ts +1 -2
- package/dist/edges/ref-validation.js +33 -13
- package/dist/edges/store.d.ts +1 -3
- package/dist/edges/store.js +0 -214
- package/dist/edges/types.d.ts +10 -0
- package/dist/embedding-client.d.ts +0 -17
- package/dist/embedding-client.js +0 -80
- package/dist/embedding-server/mobile/auth.d.ts +1 -10
- package/dist/embedding-server/mobile/auth.js +0 -15
- package/dist/embeddings.d.ts +0 -12
- package/dist/embeddings.js +0 -68
- package/dist/entities/audit-metrics.d.ts +0 -5
- package/dist/entities/audit-metrics.js +0 -4
- package/dist/entities/candidate-generator.d.ts +1 -2
- package/dist/entities/candidate-generator.js +0 -412
- package/dist/entities/entity-list.d.ts +0 -1
- package/dist/entities/entity-list.js +0 -96
- package/dist/entities/entity-orphan-list.d.ts +0 -9
- package/dist/entities/entity-orphan-list.js +0 -88
- package/dist/entities/entity-search.d.ts +0 -1
- package/dist/entities/entity-search.js +0 -147
- package/dist/entities/errors.d.ts +0 -10
- package/dist/entities/errors.js +1 -25
- package/dist/entities/lineage-store.d.ts +0 -23
- package/dist/entities/lineage-store.js +0 -104
- package/dist/entities/policy-store.d.ts +0 -9
- package/dist/entities/policy-store.js +0 -188
- package/dist/entities/provenance-query.d.ts +0 -1
- package/dist/entities/provenance-query.js +0 -164
- package/dist/entities/resolution-engine.d.ts +1 -8
- package/dist/entities/resolution-engine.js +0 -66
- package/dist/entities/rollback-preview.d.ts +0 -4
- package/dist/entities/rollback-preview.js +0 -232
- package/dist/entities/store.d.ts +1 -10
- package/dist/entities/store.js +0 -49
- package/dist/index.d.ts +15 -31
- package/dist/index.js +4 -46
- package/dist/mama-api.d.ts +19 -1
- package/dist/mama-api.js +97 -2
- package/dist/memory/api.d.ts +8 -0
- package/dist/memory/api.js +55 -2
- package/dist/memory/event-store.d.ts +0 -1
- package/dist/memory/event-store.js +0 -15
- package/dist/memory/finding-store.d.ts +0 -1
- package/dist/memory/finding-store.js +0 -12
- package/dist/memory/scope-backfill.d.ts +0 -3
- package/dist/memory/scope-backfill.js +0 -74
- package/dist/memory/scope-store.d.ts +0 -1
- package/dist/memory/scope-store.js +0 -4
- package/dist/memory/truth-store.d.ts +0 -3
- package/dist/memory/truth-store.js +0 -22
- package/dist/memory/types.d.ts +0 -1
- package/dist/memory/types.js +0 -13
- package/dist/memory-store.d.ts +0 -16
- package/dist/memory-store.js +0 -51
- package/dist/model-runs/tool-trace-store.js +9 -5
- package/dist/model-runs/types.d.ts +3 -0
- package/dist/ollama-client.d.ts +0 -9
- package/dist/ollama-client.js +0 -125
- package/dist/outcome-tracker.d.ts +0 -14
- package/dist/outcome-tracker.js +0 -44
- package/dist/progress-indicator.d.ts +0 -4
- package/dist/progress-indicator.js +0 -7
- package/dist/provenance/source-ref.d.ts +0 -9
- package/dist/provenance/source-ref.js +0 -145
- package/dist/query-intent.d.ts +0 -4
- package/dist/query-intent.js +0 -30
- package/dist/relevance-scorer.d.ts +0 -9
- package/dist/relevance-scorer.js +0 -81
- package/dist/search/feedback-store.d.ts +0 -1
- package/dist/search/feedback-store.js +0 -4
- package/dist/search/ranker-rescore.d.ts +0 -3
- package/dist/search/ranker-rescore.js +0 -27
- package/dist/search/ranker-trainer.d.ts +0 -8
- package/dist/search/ranker-trainer.js +0 -376
- package/dist/tier-validator.d.ts +0 -12
- package/dist/tier-validator.js +0 -56
- package/package.json +1 -10
- package/dist/cases/case-links.d.ts +0 -116
- package/dist/cases/case-links.js +0 -794
- package/dist/cases/composition-overrides.d.ts +0 -90
- package/dist/cases/composition-overrides.js +0 -724
- package/dist/cases/corrections.d.ts +0 -156
- package/dist/cases/corrections.js +0 -1045
- package/dist/cases/freshness.d.ts +0 -57
- package/dist/cases/freshness.js +0 -283
- package/dist/cases/live-state.d.ts +0 -48
- package/dist/cases/live-state.js +0 -256
- package/dist/cases/membership-explain.d.ts +0 -56
- package/dist/cases/membership-explain.js +0 -140
- package/dist/cases/membership-matcher.d.ts +0 -23
- package/dist/cases/membership-matcher.js +0 -193
- package/dist/cases/merge-split.d.ts +0 -61
- package/dist/cases/merge-split.js +0 -368
- package/dist/cases/role-inference.d.ts +0 -10
- package/dist/cases/role-inference.js +0 -85
- package/dist/cases/sqlite-transaction.d.ts +0 -10
- package/dist/cases/sqlite-transaction.js +0 -62
- package/dist/cases/target-ref.d.ts +0 -25
- package/dist/cases/target-ref.js +0 -22
- package/dist/cases/tombstone-sweeper.d.ts +0 -13
- package/dist/cases/tombstone-sweeper.js +0 -128
- package/dist/entities/entity-impact.d.ts +0 -41
- package/dist/entities/entity-impact.js +0 -140
- package/dist/entities/exact-merge-backfill.d.ts +0 -11
- package/dist/entities/exact-merge-backfill.js +0 -161
- package/dist/entities/lineage-backfill.d.ts +0 -12
- package/dist/entities/lineage-backfill.js +0 -101
- package/dist/memory-inject.d.ts +0 -24
- package/dist/memory-inject.js +0 -116
|
@@ -8,6 +8,7 @@ exports.normalizeSeedRefs = normalizeSeedRefs;
|
|
|
8
8
|
const node_crypto_1 = require("node:crypto");
|
|
9
9
|
const types_js_1 = require("../memory/types.js");
|
|
10
10
|
const ref_js_1 = require("./ref.js");
|
|
11
|
+
const channel_grant_js_1 = require("./channel-grant.js");
|
|
11
12
|
const SCOPE_ORDER = {
|
|
12
13
|
project: 0,
|
|
13
14
|
channel: 1,
|
|
@@ -110,13 +111,36 @@ function assertContextBoundaryAllowsInput(input) {
|
|
|
110
111
|
throw new Error('Requested tenant is outside the context boundary');
|
|
111
112
|
}
|
|
112
113
|
const seedRefs = (0, ref_js_1.normalizeContextRefs)(input.seedRefs);
|
|
113
|
-
assertSeedRefsAllowed(seedRefs, boundaryConnectors, hasConnectorBoundary);
|
|
114
|
-
}
|
|
115
|
-
|
|
114
|
+
assertSeedRefsAllowed(seedRefs, boundaryConnectors, hasConnectorBoundary, input.boundary.channels);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* A seed ref must satisfy the same visibility rule as a row the reader would have returned.
|
|
118
|
+
*
|
|
119
|
+
* The connector check alone was never enough, and once raw visibility is decided by
|
|
120
|
+
* (connector, channel) it is plainly not: a caller could name the raw id of an event in an
|
|
121
|
+
* ungranted channel and have its identifiers - upstream source id and channel - come back
|
|
122
|
+
* in the packet's source_refs, which is then persisted. That is a citation path reaching
|
|
123
|
+
* past the reading path, the exact asymmetry this rebuild exists to remove.
|
|
124
|
+
*
|
|
125
|
+
* The channel is checked only when the boundary carries a grant. Without one there is no
|
|
126
|
+
* channel rule to enforce and the connector check stands, unchanged.
|
|
127
|
+
*/
|
|
128
|
+
function assertSeedRefsAllowed(seedRefs, boundaryConnectors, hasConnectorBoundary, channelGrant) {
|
|
116
129
|
for (const ref of seedRefs) {
|
|
117
|
-
if (ref.kind
|
|
130
|
+
if (ref.kind !== 'raw')
|
|
131
|
+
continue;
|
|
132
|
+
if (hasConnectorBoundary && !boundaryConnectors.has(ref.connector)) {
|
|
118
133
|
throw new Error(`Seed raw ref connector is outside the context boundary: ${ref.connector}`);
|
|
119
134
|
}
|
|
135
|
+
if (!channelGrant)
|
|
136
|
+
continue;
|
|
137
|
+
// Calls the shared rule rather than re-deriving membership. An inline re-derivation
|
|
138
|
+
// here already disagreed with it on the empty-channel case, which is how a fourth copy
|
|
139
|
+
// of a decision starts: not by being written as a copy, but by being written as
|
|
140
|
+
// "obviously the same check".
|
|
141
|
+
if (!(0, channel_grant_js_1.isChannelGranted)(ref.connector, ref.channel_id, channelGrant)) {
|
|
142
|
+
throw new Error(`Seed raw ref channel is outside the context boundary: ${ref.connector}`);
|
|
143
|
+
}
|
|
120
144
|
}
|
|
121
145
|
}
|
|
122
146
|
function isRecord(value) {
|
|
@@ -613,6 +613,10 @@ class NodeSQLiteAdapter extends base_adapter_js_1.DatabaseAdapter {
|
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
615
|
this.exec(`
|
|
616
|
+
CREATE INDEX IF NOT EXISTS idx_decisions_topic
|
|
617
|
+
ON decisions(topic)
|
|
618
|
+
`);
|
|
619
|
+
this.exec(`
|
|
616
620
|
CREATE INDEX IF NOT EXISTS idx_decisions_envelope_hash
|
|
617
621
|
ON decisions(envelope_hash)
|
|
618
622
|
`);
|
package/dist/db-manager.d.ts
CHANGED
|
@@ -147,11 +147,6 @@ export declare function getAdapter(): DatabaseAdapter;
|
|
|
147
147
|
*/
|
|
148
148
|
export declare function closeDB(): Promise<void>;
|
|
149
149
|
export declare function ensureMemoryScope(kind: string, externalId: string): Promise<string>;
|
|
150
|
-
export declare function bindMemoryToScope(memoryId: string, scopeId: string, isPrimary?: boolean): Promise<void>;
|
|
151
|
-
export declare function listScopesForMemory(memoryId: string): Promise<Array<{
|
|
152
|
-
kind: string;
|
|
153
|
-
id: string;
|
|
154
|
-
}>>;
|
|
155
150
|
/**
|
|
156
151
|
* Insert embedding into vector search table
|
|
157
152
|
*
|
|
@@ -301,12 +296,4 @@ export declare function fts5Search(query: string, limit?: number): Promise<{
|
|
|
301
296
|
id: string;
|
|
302
297
|
rank: number;
|
|
303
298
|
}[]>;
|
|
304
|
-
/**
|
|
305
|
-
* Re-generate all embeddings using the currently configured model.
|
|
306
|
-
* Call this after changing the embedding model in config.json.
|
|
307
|
-
*
|
|
308
|
-
* @param onProgress - Optional callback with (completed, total) counts
|
|
309
|
-
* @returns Number of embeddings regenerated
|
|
310
|
-
*/
|
|
311
|
-
export declare function reindexEmbeddings(onProgress?: (completed: number, total: number) => void): Promise<number>;
|
|
312
299
|
//# sourceMappingURL=db-manager.d.ts.map
|
package/dist/db-manager.js
CHANGED
|
@@ -29,8 +29,6 @@ exports.getDB = getDB;
|
|
|
29
29
|
exports.getAdapter = getAdapter;
|
|
30
30
|
exports.closeDB = closeDB;
|
|
31
31
|
exports.ensureMemoryScope = ensureMemoryScope;
|
|
32
|
-
exports.bindMemoryToScope = bindMemoryToScope;
|
|
33
|
-
exports.listScopesForMemory = listScopesForMemory;
|
|
34
32
|
exports.insertEmbedding = insertEmbedding;
|
|
35
33
|
exports.vectorSearch = vectorSearch;
|
|
36
34
|
exports.insertDecisionWithEmbedding = insertDecisionWithEmbedding;
|
|
@@ -43,7 +41,6 @@ exports.getDbPath = getDbPath;
|
|
|
43
41
|
exports.resetDBState = resetDBState;
|
|
44
42
|
exports.isTestMode = isTestMode;
|
|
45
43
|
exports.fts5Search = fts5Search;
|
|
46
|
-
exports.reindexEmbeddings = reindexEmbeddings;
|
|
47
44
|
const path_1 = __importDefault(require("path"));
|
|
48
45
|
const os_1 = __importDefault(require("os"));
|
|
49
46
|
const debug_logger_js_1 = require("./debug-logger.js");
|
|
@@ -262,27 +259,6 @@ async function ensureMemoryScope(kind, externalId) {
|
|
|
262
259
|
.run(id, kind, externalId);
|
|
263
260
|
return id;
|
|
264
261
|
}
|
|
265
|
-
async function bindMemoryToScope(memoryId, scopeId, isPrimary = false) {
|
|
266
|
-
const adapter = getAdapter();
|
|
267
|
-
adapter
|
|
268
|
-
.prepare(`
|
|
269
|
-
INSERT OR REPLACE INTO memory_scope_bindings (memory_id, scope_id, is_primary)
|
|
270
|
-
VALUES (?, ?, ?)
|
|
271
|
-
`)
|
|
272
|
-
.run(memoryId, scopeId, isPrimary ? 1 : 0);
|
|
273
|
-
}
|
|
274
|
-
async function listScopesForMemory(memoryId) {
|
|
275
|
-
const adapter = getAdapter();
|
|
276
|
-
return adapter
|
|
277
|
-
.prepare(`
|
|
278
|
-
SELECT ms.kind, ms.external_id AS id
|
|
279
|
-
FROM memory_scope_bindings msb
|
|
280
|
-
JOIN memory_scopes ms ON ms.id = msb.scope_id
|
|
281
|
-
WHERE msb.memory_id = ?
|
|
282
|
-
ORDER BY msb.is_primary DESC, ms.created_at ASC
|
|
283
|
-
`)
|
|
284
|
-
.all(memoryId);
|
|
285
|
-
}
|
|
286
262
|
/**
|
|
287
263
|
* Insert embedding into vector search table
|
|
288
264
|
*
|
|
@@ -811,46 +787,4 @@ async function fts5Search(query, limit = 10) {
|
|
|
811
787
|
`);
|
|
812
788
|
return stmt.all(query, limit);
|
|
813
789
|
}
|
|
814
|
-
/**
|
|
815
|
-
* Re-generate all embeddings using the currently configured model.
|
|
816
|
-
* Call this after changing the embedding model in config.json.
|
|
817
|
-
*
|
|
818
|
-
* @param onProgress - Optional callback with (completed, total) counts
|
|
819
|
-
* @returns Number of embeddings regenerated
|
|
820
|
-
*/
|
|
821
|
-
async function reindexEmbeddings(onProgress) {
|
|
822
|
-
const adapter = getAdapter();
|
|
823
|
-
const { generateEnhancedEmbedding } = await import('./embeddings.js');
|
|
824
|
-
const decisions = adapter
|
|
825
|
-
.prepare('SELECT rowid, topic, decision, reasoning, outcome, confidence FROM decisions')
|
|
826
|
-
.all();
|
|
827
|
-
if (typeof adapter.insertEmbedding !== 'function') {
|
|
828
|
-
throw new Error('Embedding insertion is not available on this adapter');
|
|
829
|
-
}
|
|
830
|
-
const total = decisions.length;
|
|
831
|
-
let completed = 0;
|
|
832
|
-
for (const row of decisions) {
|
|
833
|
-
try {
|
|
834
|
-
// e5 passage role (default) - stored vector
|
|
835
|
-
const embedding = await generateEnhancedEmbedding({
|
|
836
|
-
topic: row.topic,
|
|
837
|
-
decision: row.decision,
|
|
838
|
-
reasoning: row.reasoning || undefined,
|
|
839
|
-
outcome: row.outcome || undefined,
|
|
840
|
-
confidence: row.confidence ?? undefined,
|
|
841
|
-
});
|
|
842
|
-
adapter.insertEmbedding(row.rowid, embedding);
|
|
843
|
-
completed++;
|
|
844
|
-
if (onProgress && completed % 50 === 0) {
|
|
845
|
-
onProgress(completed, total);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
catch (e) {
|
|
849
|
-
(0, debug_logger_js_1.error)(`[db-manager] Failed to reindex rowid ${row.rowid}: ${e}`);
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
onProgress?.(completed, total);
|
|
853
|
-
(0, debug_logger_js_1.info)(`[db-manager] Reindexed ${completed}/${total} embeddings`);
|
|
854
|
-
return completed;
|
|
855
|
-
}
|
|
856
790
|
//# sourceMappingURL=db-manager.js.map
|
|
@@ -140,13 +140,6 @@ export declare function ensureTokenBudget(text: string, maxTokens: number): stri
|
|
|
140
140
|
* Heuristic: ~1 token per 4 characters
|
|
141
141
|
*/
|
|
142
142
|
export declare function estimateTokens(text: string): number;
|
|
143
|
-
/**
|
|
144
|
-
* Format context in Claude-friendly Instant Answer format
|
|
145
|
-
*
|
|
146
|
-
* Story 014.7.10: Claude-Friendly Context Formatting
|
|
147
|
-
* AC #1: Instant Answer format with trust components
|
|
148
|
-
*/
|
|
149
|
-
export declare function formatInstantAnswer(decision: DecisionForFormat | null, options?: FormatOptions): string | null;
|
|
150
143
|
/**
|
|
151
144
|
* Extract quick answer from decision
|
|
152
145
|
*/
|
|
@@ -161,10 +154,6 @@ export declare function extractCodeExample(decision: DecisionForFormat): string
|
|
|
161
154
|
* Story 014.7.10 AC #2: Trust Context display
|
|
162
155
|
*/
|
|
163
156
|
export declare function formatTrustContext(trustCtx: TrustContext | null | undefined): string | null;
|
|
164
|
-
/**
|
|
165
|
-
* Format decision as curiosity-inducing teaser
|
|
166
|
-
*/
|
|
167
|
-
export declare function formatTeaser(decision: DecisionForFormat | null): string | null;
|
|
168
157
|
/**
|
|
169
158
|
* Format mama.recall() results in readable format
|
|
170
159
|
*/
|
|
@@ -17,11 +17,9 @@ exports.formatContext = formatContext;
|
|
|
17
17
|
exports.formatLegacyContext = formatLegacyContext;
|
|
18
18
|
exports.ensureTokenBudget = ensureTokenBudget;
|
|
19
19
|
exports.estimateTokens = estimateTokens;
|
|
20
|
-
exports.formatInstantAnswer = formatInstantAnswer;
|
|
21
20
|
exports.extractQuickAnswer = extractQuickAnswer;
|
|
22
21
|
exports.extractCodeExample = extractCodeExample;
|
|
23
22
|
exports.formatTrustContext = formatTrustContext;
|
|
24
|
-
exports.formatTeaser = formatTeaser;
|
|
25
23
|
exports.formatRecall = formatRecall;
|
|
26
24
|
exports.formatList = formatList;
|
|
27
25
|
const relevance_scorer_js_1 = require("./relevance-scorer.js");
|
|
@@ -362,42 +360,6 @@ function getOutcomeEmoji(outcome) {
|
|
|
362
360
|
};
|
|
363
361
|
return outcome ? emojiMap[outcome] || '' : '';
|
|
364
362
|
}
|
|
365
|
-
/**
|
|
366
|
-
* Format context in Claude-friendly Instant Answer format
|
|
367
|
-
*
|
|
368
|
-
* Story 014.7.10: Claude-Friendly Context Formatting
|
|
369
|
-
* AC #1: Instant Answer format with trust components
|
|
370
|
-
*/
|
|
371
|
-
function formatInstantAnswer(decision, options = {}) {
|
|
372
|
-
const { maxTokens = 500 } = options;
|
|
373
|
-
if (!decision) {
|
|
374
|
-
return null;
|
|
375
|
-
}
|
|
376
|
-
// Extract quick answer (first line of decision)
|
|
377
|
-
const quickAnswer = extractQuickAnswer(decision);
|
|
378
|
-
if (!quickAnswer) {
|
|
379
|
-
return null;
|
|
380
|
-
}
|
|
381
|
-
// Extract code example (from reasoning)
|
|
382
|
-
const codeExample = extractCodeExample(decision);
|
|
383
|
-
// Format trust context
|
|
384
|
-
const trustSection = formatTrustContext(typeof decision.trust_context === 'string'
|
|
385
|
-
? parseTrustContext(decision.trust_context)
|
|
386
|
-
: decision.trust_context);
|
|
387
|
-
// Build output
|
|
388
|
-
let output = `⚡ INSTANT ANSWER\n\n${quickAnswer}`;
|
|
389
|
-
if (codeExample) {
|
|
390
|
-
output += `\n\n${codeExample}`;
|
|
391
|
-
}
|
|
392
|
-
if (trustSection) {
|
|
393
|
-
output += `\n\n${trustSection}`;
|
|
394
|
-
}
|
|
395
|
-
// Token budget check
|
|
396
|
-
if (estimateTokens(output) > maxTokens) {
|
|
397
|
-
output = truncateToFit(output, maxTokens);
|
|
398
|
-
}
|
|
399
|
-
return output;
|
|
400
|
-
}
|
|
401
363
|
/**
|
|
402
364
|
* Extract quick answer from decision
|
|
403
365
|
*/
|
|
@@ -500,50 +462,6 @@ function formatTrustContext(trustCtx) {
|
|
|
500
462
|
lines.push('━'.repeat(40));
|
|
501
463
|
return lines.join('\n');
|
|
502
464
|
}
|
|
503
|
-
/**
|
|
504
|
-
* Truncate output to fit token budget
|
|
505
|
-
*/
|
|
506
|
-
function truncateToFit(output, maxTokens) {
|
|
507
|
-
const sections = output.split('\n\n');
|
|
508
|
-
const quickAnswer = sections[0];
|
|
509
|
-
let result = quickAnswer;
|
|
510
|
-
let remainingTokens = maxTokens - estimateTokens(result);
|
|
511
|
-
// Try to add code example
|
|
512
|
-
const codeIndex = sections.findIndex((s) => s.startsWith('```'));
|
|
513
|
-
if (codeIndex > 0) {
|
|
514
|
-
const codeSection = sections[codeIndex];
|
|
515
|
-
const codeTokens = estimateTokens(codeSection);
|
|
516
|
-
if (codeTokens <= remainingTokens) {
|
|
517
|
-
result += '\n\n' + codeSection;
|
|
518
|
-
remainingTokens -= codeTokens;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
// Try to add trust section (trimmed if needed)
|
|
522
|
-
const trustIndex = sections.findIndex((s) => s.startsWith('━'));
|
|
523
|
-
if (trustIndex > 0 && remainingTokens > 50) {
|
|
524
|
-
const trustSection = sections[trustIndex];
|
|
525
|
-
const trustTokens = estimateTokens(trustSection);
|
|
526
|
-
if (trustTokens <= remainingTokens) {
|
|
527
|
-
result += '\n\n' + trustSection;
|
|
528
|
-
}
|
|
529
|
-
else {
|
|
530
|
-
const trustLines = trustSection.split('\n');
|
|
531
|
-
let trimmed = trustLines[0] + '\n' + trustLines[1] + '\n';
|
|
532
|
-
for (let i = 2; i < trustLines.length - 1; i++) {
|
|
533
|
-
const line = trustLines[i] + '\n';
|
|
534
|
-
if (estimateTokens(trimmed + line) <= remainingTokens - 10) {
|
|
535
|
-
trimmed += line;
|
|
536
|
-
}
|
|
537
|
-
else {
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
trimmed += trustLines[trustLines.length - 1];
|
|
542
|
-
result += '\n\n' + trimmed;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
return result;
|
|
546
|
-
}
|
|
547
465
|
/**
|
|
548
466
|
* Format multiple decisions as Google-style search results
|
|
549
467
|
*/
|
|
@@ -578,46 +496,6 @@ function formatTeaserList(decisions, topN = 3) {
|
|
|
578
496
|
}
|
|
579
497
|
return output;
|
|
580
498
|
}
|
|
581
|
-
/**
|
|
582
|
-
* Format decision as curiosity-inducing teaser
|
|
583
|
-
*/
|
|
584
|
-
function formatTeaser(decision) {
|
|
585
|
-
if (!decision) {
|
|
586
|
-
return null;
|
|
587
|
-
}
|
|
588
|
-
const timeAgo = calculateDuration(getDecisionTimestamp(decision));
|
|
589
|
-
// Extract preview (first 60 chars)
|
|
590
|
-
const preview = decision.decision.length > 60 ? decision.decision.substring(0, 60) + '...' : decision.decision;
|
|
591
|
-
// Extract files from trust_context or show generic
|
|
592
|
-
let files = 'Multiple files';
|
|
593
|
-
const trustCtx = typeof decision.trust_context === 'string'
|
|
594
|
-
? parseTrustContext(decision.trust_context)
|
|
595
|
-
: decision.trust_context;
|
|
596
|
-
if (trustCtx?.source?.file) {
|
|
597
|
-
const fileStr = trustCtx.source.file;
|
|
598
|
-
const fileList = fileStr.split(',').map((f) => f.trim());
|
|
599
|
-
if (fileList.length === 1) {
|
|
600
|
-
files = fileList[0];
|
|
601
|
-
}
|
|
602
|
-
else if (fileList.length === 2) {
|
|
603
|
-
files = fileList.join(', ');
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
files = `${fileList[0]}, ${fileList[1]} (+${fileList.length - 2})`;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
const teaser = `
|
|
610
|
-
💡 MAMA has related info
|
|
611
|
-
|
|
612
|
-
📚 Topic: ${decision.topic}
|
|
613
|
-
📖 Preview: "${preview}"
|
|
614
|
-
📁 Files: ${files}
|
|
615
|
-
⏰ Updated: ${timeAgo}
|
|
616
|
-
|
|
617
|
-
🔍 Read more: mama.recall('${decision.topic}')
|
|
618
|
-
`.trim();
|
|
619
|
-
return teaser;
|
|
620
|
-
}
|
|
621
499
|
/**
|
|
622
500
|
* Format mama.recall() results in readable format
|
|
623
501
|
*/
|
|
@@ -163,18 +163,6 @@ export declare function createEdgesFromReasoning(fromId: string, reasoning: stri
|
|
|
163
163
|
created: number;
|
|
164
164
|
failed: number;
|
|
165
165
|
}>;
|
|
166
|
-
/**
|
|
167
|
-
* Get supersedes chain depth for a topic
|
|
168
|
-
*
|
|
169
|
-
* Story 2.2: Calculate how many times a topic has been superseded
|
|
170
|
-
*
|
|
171
|
-
* @param topic - Decision topic
|
|
172
|
-
* @returns Chain depth and decision IDs
|
|
173
|
-
*/
|
|
174
|
-
export declare function getSupersededChainDepth(topic: string): Promise<{
|
|
175
|
-
depth: number;
|
|
176
|
-
chain: string[];
|
|
177
|
-
}>;
|
|
178
166
|
/**
|
|
179
167
|
* Learn Decision Function (Main API)
|
|
180
168
|
*
|
package/dist/decision-tracker.js
CHANGED
|
@@ -25,7 +25,6 @@ exports.calculateCombinedConfidence = calculateCombinedConfidence;
|
|
|
25
25
|
exports.detectRefinement = detectRefinement;
|
|
26
26
|
exports.parseReasoningForRelationships = parseReasoningForRelationships;
|
|
27
27
|
exports.createEdgesFromReasoning = createEdgesFromReasoning;
|
|
28
|
-
exports.getSupersededChainDepth = getSupersededChainDepth;
|
|
29
28
|
exports.learnDecision = learnDecision;
|
|
30
29
|
exports.updateConfidence = updateConfidence;
|
|
31
30
|
const debug_logger_js_1 = require("./debug-logger.js");
|
|
@@ -305,55 +304,6 @@ async function createEdgesFromReasoning(fromId, reasoning) {
|
|
|
305
304
|
}
|
|
306
305
|
return { created, failed };
|
|
307
306
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Get supersedes chain depth for a topic
|
|
310
|
-
*
|
|
311
|
-
* Story 2.2: Calculate how many times a topic has been superseded
|
|
312
|
-
*
|
|
313
|
-
* @param topic - Decision topic
|
|
314
|
-
* @returns Chain depth and decision IDs
|
|
315
|
-
*/
|
|
316
|
-
async function getSupersededChainDepth(topic) {
|
|
317
|
-
const adapter = (0, memory_store_js_1.getAdapter)();
|
|
318
|
-
const chain = [];
|
|
319
|
-
try {
|
|
320
|
-
// Start from the latest decision (superseded_by IS NULL)
|
|
321
|
-
let stmt = adapter.prepare(`
|
|
322
|
-
SELECT id, supersedes FROM decisions
|
|
323
|
-
WHERE topic = ? AND superseded_by IS NULL
|
|
324
|
-
ORDER BY created_at DESC
|
|
325
|
-
LIMIT 1
|
|
326
|
-
`);
|
|
327
|
-
let current = stmt.get(topic);
|
|
328
|
-
if (!current) {
|
|
329
|
-
return { depth: 0, chain: [] };
|
|
330
|
-
}
|
|
331
|
-
chain.push(current.id);
|
|
332
|
-
// Walk back through supersedes chain with cycle detection
|
|
333
|
-
const visited = new Set([current.id]);
|
|
334
|
-
const MAX_CHAIN_DEPTH = 1000; // Safety limit
|
|
335
|
-
while (current && current.supersedes && chain.length < MAX_CHAIN_DEPTH) {
|
|
336
|
-
// Cycle detection: stop if we've seen this ID before
|
|
337
|
-
if (visited.has(current.supersedes)) {
|
|
338
|
-
break;
|
|
339
|
-
}
|
|
340
|
-
stmt = adapter.prepare('SELECT id, supersedes FROM decisions WHERE id = ?');
|
|
341
|
-
current = stmt.get(current.supersedes);
|
|
342
|
-
if (current) {
|
|
343
|
-
visited.add(current.id);
|
|
344
|
-
chain.push(current.id);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return {
|
|
348
|
-
depth: chain.length - 1, // depth = number of supersedes edges
|
|
349
|
-
chain: chain.reverse(), // oldest to newest
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
catch (error) {
|
|
353
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
354
|
-
throw new Error(`Failed to get supersedes chain: ${message}`);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
307
|
// ════════════════════════════════════════════════════════════════════════════
|
|
358
308
|
// NOTE: Auto-link functions REMOVED in v1.2.0
|
|
359
309
|
//
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { DatabaseAdapter } from '../db-manager.js';
|
|
2
|
-
import type { ListVisibleTwinEdgesOptions, TwinEdgeRecord, TwinRef,
|
|
2
|
+
import type { ListVisibleTwinEdgesOptions, TwinEdgeRecord, TwinRef, TwinVisibility } from './types.js';
|
|
3
3
|
type TwinRefVisibilityAdapter = Pick<DatabaseAdapter, 'prepare'>;
|
|
4
4
|
export declare function assertTwinRefsVisible(adapter: TwinRefVisibilityAdapter, refs: readonly TwinRef[], visibility?: TwinVisibility): void;
|
|
5
|
-
export declare function assertTwinRefsVisibleToScopes(adapter: TwinRefVisibilityAdapter, refs: readonly TwinRef[], scopes?: TwinScopeRef[]): void;
|
|
6
5
|
export declare function listVisibleTwinEdgesForRefs(adapter: TwinRefVisibilityAdapter, refs: readonly TwinRef[], options?: ListVisibleTwinEdgesOptions): TwinEdgeRecord[];
|
|
7
6
|
export {};
|
|
8
7
|
//# sourceMappingURL=ref-validation.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.assertTwinRefsVisible = assertTwinRefsVisible;
|
|
4
|
-
exports.assertTwinRefsVisibleToScopes = assertTwinRefsVisibleToScopes;
|
|
5
4
|
exports.listVisibleTwinEdgesForRefs = listVisibleTwinEdgesForRefs;
|
|
6
5
|
const store_js_1 = require("./store.js");
|
|
6
|
+
const channel_grant_js_1 = require("../context-compile/channel-grant.js");
|
|
7
7
|
const TABLE_COLUMN_PRAGMAS = {
|
|
8
8
|
decisions: 'PRAGMA table_info(decisions)',
|
|
9
9
|
case_truth: 'PRAGMA table_info(case_truth)',
|
|
@@ -21,9 +21,6 @@ function hasScopes(scopes) {
|
|
|
21
21
|
function hasProjectRefs(projectRefs) {
|
|
22
22
|
return Array.isArray(projectRefs) && projectRefs.length > 0;
|
|
23
23
|
}
|
|
24
|
-
function visibilityFromScopes(scopes) {
|
|
25
|
-
return { scopes: scopes ? [...scopes] : undefined };
|
|
26
|
-
}
|
|
27
24
|
function asOfMs(visibility) {
|
|
28
25
|
return typeof visibility.asOfMs === 'number' ? visibility.asOfMs : null;
|
|
29
26
|
}
|
|
@@ -177,6 +174,30 @@ function isCaseVisible(adapter, id, visibility) {
|
|
|
177
174
|
}
|
|
178
175
|
return false;
|
|
179
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* The time bound, shared by both branches so a grant cannot skip it.
|
|
179
|
+
*
|
|
180
|
+
* DELIBERATELY STRICTER THAN THE READER, and a review flagged the difference as a
|
|
181
|
+
* divergence between two delegates of one rule. It is not. A row with no usable timestamp
|
|
182
|
+
* is refused here even when no bound is set, while the reader - whose clause is on
|
|
183
|
+
* `COALESCE(event_datetime, source_timestamp_ms)` - leaves such a row alone when there is
|
|
184
|
+
* no bound to apply.
|
|
185
|
+
*
|
|
186
|
+
* The direction is what makes it correct: this gate guards refs reached INDIRECTLY, through
|
|
187
|
+
* a seed the caller named or an edge the graph walked. Refusing what cannot be shown to sit
|
|
188
|
+
* inside any window keeps the indirect path no wider than the direct one, which is the
|
|
189
|
+
* invariant the whole design rests on. Relaxing it to match the reader would have made
|
|
190
|
+
* citation reach further than reading for exactly the rows whose position in time is
|
|
191
|
+
* unknown. `fails closed for raw endpoints with blank timestamps` states the intent.
|
|
192
|
+
*/
|
|
193
|
+
function isRawWithinTime(row, visibility) {
|
|
194
|
+
const rawTs = row.event_datetime ?? row.source_timestamp_ms;
|
|
195
|
+
if (rawTs === null || rawTs === undefined || (typeof rawTs === 'string' && rawTs.trim() === '')) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const eventTsMs = parseTimestamp(rawTs);
|
|
199
|
+
return eventTsMs !== null && eventTsMs >= 0 && isWithinVisibilityTime(eventTsMs, visibility);
|
|
200
|
+
}
|
|
180
201
|
function isRawVisible(adapter, id, visibility) {
|
|
181
202
|
const row = adapter
|
|
182
203
|
.prepare('SELECT * FROM connector_event_index WHERE event_index_id = ? LIMIT 1')
|
|
@@ -188,6 +209,13 @@ function isRawVisible(adapter, id, visibility) {
|
|
|
188
209
|
!visibility.connectors.includes(String(row.source_connector))) {
|
|
189
210
|
return false;
|
|
190
211
|
}
|
|
212
|
+
// The grant decides, and it decides the same way here as in the reader - one rule, taken
|
|
213
|
+
// from one place. The scope/project/tenant clauses below are the pre-grant rule and are
|
|
214
|
+
// skipped when a grant is present, exactly as the reader skips them, because applying
|
|
215
|
+
// both would make a cited ref satisfy a stricter test than a read one.
|
|
216
|
+
if (visibility.channels) {
|
|
217
|
+
return ((0, channel_grant_js_1.isChannelGranted)(String(row.source_connector), typeof row.channel === 'string' ? row.channel : null, visibility.channels) && isRawWithinTime(row, visibility));
|
|
218
|
+
}
|
|
191
219
|
if (hasProjectRefs(visibility.projectRefs) &&
|
|
192
220
|
!visibility.projectRefs.some((project) => project.id === row.project_id)) {
|
|
193
221
|
return false;
|
|
@@ -197,12 +225,7 @@ function isRawVisible(adapter, id, visibility) {
|
|
|
197
225
|
row.tenant_id !== visibility.tenantId) {
|
|
198
226
|
return false;
|
|
199
227
|
}
|
|
200
|
-
|
|
201
|
-
if (rawTs === null || rawTs === undefined || (typeof rawTs === 'string' && rawTs.trim() === '')) {
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
const eventTsMs = parseTimestamp(rawTs);
|
|
205
|
-
if (eventTsMs === null || eventTsMs < 0 || !isWithinVisibilityTime(eventTsMs, visibility)) {
|
|
228
|
+
if (!isRawWithinTime(row, visibility)) {
|
|
206
229
|
return false;
|
|
207
230
|
}
|
|
208
231
|
if (!hasScopes(visibility.scopes)) {
|
|
@@ -269,9 +292,6 @@ function assertTwinRefsVisible(adapter, refs, visibility = {}) {
|
|
|
269
292
|
}
|
|
270
293
|
}
|
|
271
294
|
}
|
|
272
|
-
function assertTwinRefsVisibleToScopes(adapter, refs, scopes) {
|
|
273
|
-
assertTwinRefsVisible(adapter, refs, visibilityFromScopes(scopes));
|
|
274
|
-
}
|
|
275
295
|
function listVisibleTwinEdgesForRefs(adapter, refs, options = {}) {
|
|
276
296
|
const edgeCache = new Map();
|
|
277
297
|
const edgeTypes = normalizeEdgeTypes(options.edgeTypes);
|
package/dist/edges/store.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { DatabaseAdapter } from '../db-manager.js';
|
|
2
|
-
import { type
|
|
2
|
+
import { type TwinEdgeRecord, type TwinRef } from './types.js';
|
|
3
3
|
type TwinEdgeReadAdapter = Pick<DatabaseAdapter, 'prepare'>;
|
|
4
|
-
type TwinEdgeAdapter = Pick<DatabaseAdapter, 'prepare' | 'transaction'>;
|
|
5
4
|
export declare function mapTwinEdgeRow(row: Record<string, unknown>): TwinEdgeRecord;
|
|
6
5
|
export declare function getTwinEdge(adapter: TwinEdgeReadAdapter, edgeId: string): TwinEdgeRecord | null;
|
|
7
6
|
export declare function listTwinEdgesForRefs(adapter: TwinEdgeReadAdapter, refs: readonly TwinRef[]): TwinEdgeRecord[];
|
|
8
|
-
export declare function insertTwinEdge(adapter: TwinEdgeAdapter, input: InsertTwinEdgeInput): TwinEdgeRecord;
|
|
9
7
|
export {};
|
|
10
8
|
//# sourceMappingURL=store.d.ts.map
|