@jungjaehoon/mama-core 1.6.0 → 1.7.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/037-create-context-packets.sql +32 -0
- package/dist/cases/wiki-page-index.js +6 -2
- package/dist/context-compile/boundary-defaults.d.ts +12 -0
- package/dist/context-compile/boundary-defaults.js +105 -0
- package/dist/context-compile/compiler-policy.d.ts +39 -0
- package/dist/context-compile/compiler-policy.js +147 -0
- package/dist/context-compile/compiler.d.ts +18 -0
- package/dist/context-compile/compiler.js +401 -0
- package/dist/context-compile/index.d.ts +9 -0
- package/dist/context-compile/index.js +25 -0
- package/dist/context-compile/packet-store.d.ts +9 -0
- package/dist/context-compile/packet-store.js +255 -0
- package/dist/context-compile/ref.d.ts +7 -0
- package/dist/context-compile/ref.js +102 -0
- package/dist/context-compile/source-readers.d.ts +69 -0
- package/dist/context-compile/source-readers.js +707 -0
- package/dist/context-compile/types.d.ts +138 -0
- package/dist/context-compile/types.js +11 -0
- package/dist/context-compile/visibility.d.ts +21 -0
- package/dist/context-compile/visibility.js +200 -0
- package/dist/db-adapter/node-sqlite-adapter.d.ts +3 -0
- package/dist/db-adapter/node-sqlite-adapter.js +76 -0
- package/dist/edges/ref-validation.js +55 -16
- package/dist/edges/types.d.ts +2 -0
- package/dist/embeddings.d.ts +3 -0
- package/dist/embeddings.js +37 -10
- package/dist/entities/store.d.ts +4 -1
- package/dist/entities/store.js +206 -78
- package/dist/entities/types.d.ts +5 -1
- package/dist/entities/types.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/memory/provenance.js +1 -0
- package/dist/memory/types.d.ts +1 -0
- package/package.json +3 -2
package/dist/embeddings.js
CHANGED
|
@@ -14,7 +14,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.getQuantized = exports.getEmbeddingDim = exports.getModelName = exports.loadConfig = exports.MODEL_NAME = exports.EMBEDDING_DIM = exports.embeddingCache = void 0;
|
|
17
|
+
exports.getQuantized = exports.getEmbeddingDim = exports.getModelName = exports.loadConfig = exports.MODEL_NAME = exports.EMBEDDING_DIM = exports.embeddingCache = exports.EMBEDDING_MAX_TOKENISH_SEGMENTS = exports.EMBEDDING_MODEL_MAX_LENGTH = void 0;
|
|
18
|
+
exports.prepareEmbeddingText = prepareEmbeddingText;
|
|
18
19
|
exports.generateEmbedding = generateEmbedding;
|
|
19
20
|
exports.generateEnhancedEmbedding = generateEnhancedEmbedding;
|
|
20
21
|
exports.generateBatchEmbeddings = generateBatchEmbeddings;
|
|
@@ -33,6 +34,9 @@ Object.defineProperty(exports, "getQuantized", { enumerable: true, get: function
|
|
|
33
34
|
// Shared cache directory (not in node_modules)
|
|
34
35
|
const DEFAULT_CACHE_DIR = path_1.default.join(os_1.default.homedir(), '.cache', 'huggingface', 'transformers');
|
|
35
36
|
const TIER3_ENV_VALUES = new Set(['1', 'true', 'yes']);
|
|
37
|
+
exports.EMBEDDING_MODEL_MAX_LENGTH = 512;
|
|
38
|
+
exports.EMBEDDING_MAX_TOKENISH_SEGMENTS = 480;
|
|
39
|
+
const TOKENISH_SEGMENT_PATTERN = /[\p{Script=Hangul}\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]|\S+/gu;
|
|
36
40
|
// Singleton pattern for model loading
|
|
37
41
|
let embeddingPipeline = null;
|
|
38
42
|
let currentModelName = null;
|
|
@@ -46,6 +50,19 @@ function assertEmbeddingsEnabled() {
|
|
|
46
50
|
'Tier 3 test mode must use lexical/no-vector fallback instead of loading the embedding model.');
|
|
47
51
|
}
|
|
48
52
|
}
|
|
53
|
+
function prepareEmbeddingText(text) {
|
|
54
|
+
const trimmed = text.trim();
|
|
55
|
+
let count = 0;
|
|
56
|
+
let cutIndex = trimmed.length;
|
|
57
|
+
for (const match of trimmed.matchAll(TOKENISH_SEGMENT_PATTERN)) {
|
|
58
|
+
count++;
|
|
59
|
+
if (count > exports.EMBEDDING_MAX_TOKENISH_SEGMENTS) {
|
|
60
|
+
cutIndex = match.index ?? trimmed.length;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return cutIndex === trimmed.length ? trimmed : trimmed.slice(0, cutIndex).trimEnd();
|
|
65
|
+
}
|
|
49
66
|
/**
|
|
50
67
|
* Load embedding model (configurable)
|
|
51
68
|
*
|
|
@@ -112,12 +129,13 @@ async function loadModel() {
|
|
|
112
129
|
* @throws Error if text is empty or embedding fails
|
|
113
130
|
*/
|
|
114
131
|
async function generateEmbedding(text) {
|
|
115
|
-
if (
|
|
132
|
+
if (typeof text !== 'string' || text.trim().length === 0) {
|
|
116
133
|
throw new Error('Text cannot be empty');
|
|
117
134
|
}
|
|
118
135
|
assertEmbeddingsEnabled();
|
|
136
|
+
const preparedText = prepareEmbeddingText(text);
|
|
119
137
|
// Task 2: Check cache first (AC #3)
|
|
120
|
-
const cached = embedding_cache_js_1.embeddingCache.get(
|
|
138
|
+
const cached = embedding_cache_js_1.embeddingCache.get(preparedText);
|
|
121
139
|
if (cached) {
|
|
122
140
|
return cached;
|
|
123
141
|
}
|
|
@@ -126,9 +144,11 @@ async function generateEmbedding(text) {
|
|
|
126
144
|
const model = await loadModel();
|
|
127
145
|
const expectedDim = (0, config_loader_js_1.getEmbeddingDim)();
|
|
128
146
|
// Generate embedding
|
|
129
|
-
const output = await model(
|
|
147
|
+
const output = await model(preparedText, {
|
|
130
148
|
pooling: 'mean', // Mean pooling over tokens
|
|
131
149
|
normalize: true, // L2 normalization
|
|
150
|
+
truncation: true,
|
|
151
|
+
max_length: exports.EMBEDDING_MODEL_MAX_LENGTH,
|
|
132
152
|
});
|
|
133
153
|
// Extract Float32Array
|
|
134
154
|
const embedding = output.data;
|
|
@@ -139,7 +159,7 @@ async function generateEmbedding(text) {
|
|
|
139
159
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
140
160
|
const _latency = Date.now() - startTime;
|
|
141
161
|
// Task 2: Store in cache (AC #3)
|
|
142
|
-
embedding_cache_js_1.embeddingCache.set(
|
|
162
|
+
embedding_cache_js_1.embeddingCache.set(preparedText, embedding);
|
|
143
163
|
return embedding;
|
|
144
164
|
}
|
|
145
165
|
catch (error) {
|
|
@@ -201,14 +221,19 @@ async function generateEnhancedEmbedding(decision) {
|
|
|
201
221
|
* @returns Array of embeddings
|
|
202
222
|
*/
|
|
203
223
|
async function generateBatchEmbeddings(texts) {
|
|
204
|
-
assertEmbeddingsEnabled();
|
|
205
224
|
if (!Array.isArray(texts) || texts.length === 0) {
|
|
206
225
|
throw new Error('Texts must be a non-empty array');
|
|
207
226
|
}
|
|
208
|
-
// Validate all texts
|
|
209
227
|
for (const text of texts) {
|
|
210
|
-
if (
|
|
211
|
-
throw new Error('All texts must be non-empty');
|
|
228
|
+
if (typeof text !== 'string' || text.trim().length === 0) {
|
|
229
|
+
throw new Error('All texts must be non-empty strings');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
assertEmbeddingsEnabled();
|
|
233
|
+
const preparedTexts = texts.map((text) => prepareEmbeddingText(text));
|
|
234
|
+
for (const text of preparedTexts) {
|
|
235
|
+
if (!text || text.length === 0) {
|
|
236
|
+
throw new Error('All texts must be non-empty strings');
|
|
212
237
|
}
|
|
213
238
|
}
|
|
214
239
|
const startTime = Date.now();
|
|
@@ -217,9 +242,11 @@ async function generateBatchEmbeddings(texts) {
|
|
|
217
242
|
const expectedDim = (0, config_loader_js_1.getEmbeddingDim)();
|
|
218
243
|
// Native batch processing - single model forward pass
|
|
219
244
|
// This is significantly faster than sequential calls
|
|
220
|
-
const outputs = await model(
|
|
245
|
+
const outputs = await model(preparedTexts, {
|
|
221
246
|
pooling: 'mean',
|
|
222
247
|
normalize: true,
|
|
248
|
+
truncation: true,
|
|
249
|
+
max_length: exports.EMBEDDING_MODEL_MAX_LENGTH,
|
|
223
250
|
});
|
|
224
251
|
// Extract embeddings from batch output
|
|
225
252
|
const embeddings = [];
|
package/dist/entities/store.d.ts
CHANGED
|
@@ -13,9 +13,11 @@ export declare class EntityMergeError extends Error {
|
|
|
13
13
|
readonly code: string;
|
|
14
14
|
constructor(code: string, message: string);
|
|
15
15
|
}
|
|
16
|
+
declare const OBSERVATION_CONTEXT_KEY_COLUMNS: readonly ["workspace_context_key", "channel_context_key", "thread_context_key", "actor_context_key"];
|
|
16
17
|
type CreateEntityNodeInput = Omit<EntityNode, 'created_at' | 'updated_at'>;
|
|
17
18
|
type AttachEntityAliasInput = Omit<EntityAlias, 'created_at'>;
|
|
18
|
-
type
|
|
19
|
+
type ObservationContextKeyColumn = (typeof OBSERVATION_CONTEXT_KEY_COLUMNS)[number];
|
|
20
|
+
type UpsertEntityObservationInput = Omit<EntityObservation, 'created_at'> & Partial<Record<ObservationContextKeyColumn, string | null>>;
|
|
19
21
|
type AppendEntityTimelineEventInput = {
|
|
20
22
|
event: Omit<EntityTimelineEvent, 'id' | 'created_at'> & {
|
|
21
23
|
id?: string;
|
|
@@ -27,6 +29,7 @@ export interface UpsertEntityObservationResult {
|
|
|
27
29
|
id: string;
|
|
28
30
|
created: boolean;
|
|
29
31
|
}
|
|
32
|
+
export declare function clearEntityTableColumnCache(adapter: EntityStoreAdapter): void;
|
|
30
33
|
export declare function parseObservationRow(row: Record<string, unknown>): EntityObservation;
|
|
31
34
|
export declare function createEntityNode(input: CreateEntityNodeInput): Promise<EntityNode>;
|
|
32
35
|
export declare function getEntityNode(id: string, adapter?: EntityStoreAdapter): EntityNode | null;
|
package/dist/entities/store.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EntityMergeError = void 0;
|
|
4
|
+
exports.clearEntityTableColumnCache = clearEntityTableColumnCache;
|
|
4
5
|
exports.parseObservationRow = parseObservationRow;
|
|
5
6
|
exports.createEntityNode = createEntityNode;
|
|
6
7
|
exports.getEntityNode = getEntityNode;
|
|
@@ -25,6 +26,13 @@ class EntityMergeError extends Error {
|
|
|
25
26
|
}
|
|
26
27
|
exports.EntityMergeError = EntityMergeError;
|
|
27
28
|
const MAX_MERGE_CHAIN_DEPTH = 8;
|
|
29
|
+
const OBSERVATION_CONTEXT_KEY_COLUMNS = [
|
|
30
|
+
'workspace_context_key',
|
|
31
|
+
'channel_context_key',
|
|
32
|
+
'thread_context_key',
|
|
33
|
+
'actor_context_key',
|
|
34
|
+
];
|
|
35
|
+
const tableColumnCache = new WeakMap();
|
|
28
36
|
function now() {
|
|
29
37
|
return Date.now();
|
|
30
38
|
}
|
|
@@ -32,6 +40,58 @@ function normalizeSourceLocator(value) {
|
|
|
32
40
|
// Write empty-string as the null sentinel so SQLite UNIQUE can collapse null-like locators; parseObservationRow maps it back to null on read.
|
|
33
41
|
return value ?? '';
|
|
34
42
|
}
|
|
43
|
+
function normalizeContextKey(value) {
|
|
44
|
+
return value ?? '';
|
|
45
|
+
}
|
|
46
|
+
function sourceLocatorForInput(input) {
|
|
47
|
+
return normalizeSourceLocator(input.source_locator);
|
|
48
|
+
}
|
|
49
|
+
function channelContextKey(input) {
|
|
50
|
+
if (input.channel_context_key !== undefined) {
|
|
51
|
+
return normalizeContextKey(input.channel_context_key);
|
|
52
|
+
}
|
|
53
|
+
if (input.scope_kind !== 'channel' || !input.scope_id) {
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
return input.scope_id.startsWith(`${input.source_connector}:`)
|
|
57
|
+
? input.scope_id
|
|
58
|
+
: `${input.source_connector}:${input.scope_id}`;
|
|
59
|
+
}
|
|
60
|
+
function actorContextKey(input) {
|
|
61
|
+
if (input.actor_context_key !== undefined) {
|
|
62
|
+
return normalizeContextKey(input.actor_context_key);
|
|
63
|
+
}
|
|
64
|
+
if (input.observation_type === 'author') {
|
|
65
|
+
return input.surface_form;
|
|
66
|
+
}
|
|
67
|
+
return input.related_surface_forms.find((value) => value.trim().length > 0) ?? '';
|
|
68
|
+
}
|
|
69
|
+
function observationContextKeys(input) {
|
|
70
|
+
return {
|
|
71
|
+
workspace_context_key: normalizeContextKey(input.workspace_context_key ?? input.source_connector),
|
|
72
|
+
channel_context_key: channelContextKey(input),
|
|
73
|
+
thread_context_key: normalizeContextKey(input.thread_context_key),
|
|
74
|
+
actor_context_key: actorContextKey(input),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function tableColumnNames(adapter, tableName) {
|
|
78
|
+
let adapterCache = tableColumnCache.get(adapter);
|
|
79
|
+
if (!adapterCache) {
|
|
80
|
+
adapterCache = new Map();
|
|
81
|
+
tableColumnCache.set(adapter, adapterCache);
|
|
82
|
+
}
|
|
83
|
+
const cached = adapterCache.get(tableName);
|
|
84
|
+
if (cached) {
|
|
85
|
+
return cached;
|
|
86
|
+
}
|
|
87
|
+
const rows = adapter.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
88
|
+
const columns = new Set(rows.map((row) => row.name));
|
|
89
|
+
adapterCache.set(tableName, columns);
|
|
90
|
+
return columns;
|
|
91
|
+
}
|
|
92
|
+
function clearEntityTableColumnCache(adapter) {
|
|
93
|
+
tableColumnCache.delete(adapter);
|
|
94
|
+
}
|
|
35
95
|
function requireStringField(row, field) {
|
|
36
96
|
if (typeof row[field] !== 'string' || row[field].length === 0) {
|
|
37
97
|
throw new Error(`Invalid entity observation row: ${field} must be a non-empty string`);
|
|
@@ -134,6 +194,10 @@ function parseObservationRow(row) {
|
|
|
134
194
|
source_connector: requireStringField(row, 'source_connector'),
|
|
135
195
|
source_locator: sourceLocator && sourceLocator.length > 0 ? sourceLocator : null,
|
|
136
196
|
source_raw_record_id: requireStringField(row, 'source_raw_record_id'),
|
|
197
|
+
workspace_context_key: optionalStringFieldIfPresent(row, 'workspace_context_key'),
|
|
198
|
+
channel_context_key: optionalStringFieldIfPresent(row, 'channel_context_key'),
|
|
199
|
+
thread_context_key: optionalStringFieldIfPresent(row, 'thread_context_key'),
|
|
200
|
+
actor_context_key: optionalStringFieldIfPresent(row, 'actor_context_key'),
|
|
137
201
|
created_at: createdAt,
|
|
138
202
|
};
|
|
139
203
|
}
|
|
@@ -226,44 +290,152 @@ function listEntityAliases(entityId, adapter = (0, db_manager_js_1.getAdapter)()
|
|
|
226
290
|
created_at: Number(row.created_at),
|
|
227
291
|
}));
|
|
228
292
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const
|
|
293
|
+
function observationContextColumns(columns) {
|
|
294
|
+
return OBSERVATION_CONTEXT_KEY_COLUMNS.filter((column) => columns.has(column));
|
|
295
|
+
}
|
|
296
|
+
function observationInsertValues(input, normalizedSourceLocator, contextColumns, contextKeys, createdAt) {
|
|
297
|
+
const columns = [
|
|
298
|
+
'id',
|
|
299
|
+
'observation_type',
|
|
300
|
+
'entity_kind_hint',
|
|
301
|
+
'surface_form',
|
|
302
|
+
'normalized_form',
|
|
303
|
+
'lang',
|
|
304
|
+
'script',
|
|
305
|
+
'context_summary',
|
|
306
|
+
'related_surface_forms',
|
|
307
|
+
'timestamp_observed',
|
|
308
|
+
'scope_kind',
|
|
309
|
+
'scope_id',
|
|
310
|
+
'extractor_version',
|
|
311
|
+
'embedding_model_version',
|
|
312
|
+
'source_connector',
|
|
313
|
+
'source_locator',
|
|
314
|
+
'source_raw_record_id',
|
|
315
|
+
...contextColumns,
|
|
316
|
+
'created_at',
|
|
317
|
+
];
|
|
318
|
+
const values = [
|
|
319
|
+
input.id,
|
|
320
|
+
input.observation_type,
|
|
321
|
+
input.entity_kind_hint,
|
|
322
|
+
input.surface_form,
|
|
323
|
+
input.normalized_form,
|
|
324
|
+
input.lang,
|
|
325
|
+
input.script,
|
|
326
|
+
input.context_summary,
|
|
327
|
+
JSON.stringify(input.related_surface_forms),
|
|
328
|
+
input.timestamp_observed,
|
|
329
|
+
input.scope_kind,
|
|
330
|
+
input.scope_id,
|
|
331
|
+
input.extractor_version,
|
|
332
|
+
input.embedding_model_version,
|
|
333
|
+
input.source_connector,
|
|
334
|
+
normalizedSourceLocator,
|
|
335
|
+
input.source_raw_record_id,
|
|
336
|
+
...contextColumns.map((column) => contextKeys[column]),
|
|
337
|
+
createdAt,
|
|
338
|
+
];
|
|
339
|
+
return { columns, values };
|
|
340
|
+
}
|
|
341
|
+
function findExistingObservation(adapter, input, normalizedSourceLocator, contextColumns, contextKeys) {
|
|
342
|
+
const conditions = [
|
|
343
|
+
'source_connector = ?',
|
|
344
|
+
'source_locator = ?',
|
|
345
|
+
'source_raw_record_id = ?',
|
|
346
|
+
'observation_type = ?',
|
|
347
|
+
...contextColumns.map((column) => `COALESCE(${column}, '') = ?`),
|
|
348
|
+
];
|
|
349
|
+
const params = [
|
|
350
|
+
input.source_connector,
|
|
351
|
+
normalizedSourceLocator,
|
|
352
|
+
input.source_raw_record_id,
|
|
353
|
+
input.observation_type,
|
|
354
|
+
...contextColumns.map((column) => contextKeys[column]),
|
|
355
|
+
];
|
|
356
|
+
return adapter
|
|
357
|
+
.prepare(`
|
|
358
|
+
SELECT id FROM entity_observations
|
|
359
|
+
WHERE ${conditions.join(' AND ')}
|
|
360
|
+
ORDER BY created_at ASC, id ASC
|
|
361
|
+
LIMIT 1
|
|
362
|
+
`)
|
|
363
|
+
.get(...params);
|
|
364
|
+
}
|
|
365
|
+
function insertObservation(adapter, input, normalizedSourceLocator, contextColumns, contextKeys, createdAt) {
|
|
366
|
+
const insert = observationInsertValues(input, normalizedSourceLocator, contextColumns, contextKeys, createdAt);
|
|
367
|
+
const placeholders = insert.columns.map(() => '?').join(', ');
|
|
234
368
|
adapter
|
|
235
369
|
.prepare(`
|
|
236
|
-
INSERT INTO entity_observations (
|
|
237
|
-
|
|
238
|
-
context_summary, related_surface_forms, timestamp_observed, scope_kind, scope_id,
|
|
239
|
-
extractor_version, embedding_model_version, source_connector, source_locator,
|
|
240
|
-
source_raw_record_id, created_at
|
|
241
|
-
)
|
|
242
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
243
|
-
ON CONFLICT(source_connector, source_locator, source_raw_record_id, observation_type)
|
|
244
|
-
DO UPDATE SET
|
|
245
|
-
entity_kind_hint = excluded.entity_kind_hint,
|
|
246
|
-
surface_form = excluded.surface_form,
|
|
247
|
-
normalized_form = excluded.normalized_form,
|
|
248
|
-
lang = excluded.lang,
|
|
249
|
-
script = excluded.script,
|
|
250
|
-
context_summary = excluded.context_summary,
|
|
251
|
-
related_surface_forms = excluded.related_surface_forms,
|
|
252
|
-
timestamp_observed = excluded.timestamp_observed,
|
|
253
|
-
scope_kind = excluded.scope_kind,
|
|
254
|
-
scope_id = excluded.scope_id,
|
|
255
|
-
extractor_version = excluded.extractor_version,
|
|
256
|
-
embedding_model_version = excluded.embedding_model_version,
|
|
257
|
-
source_locator = excluded.source_locator,
|
|
258
|
-
created_at = entity_observations.created_at
|
|
370
|
+
INSERT INTO entity_observations (${insert.columns.join(', ')})
|
|
371
|
+
VALUES (${placeholders})
|
|
259
372
|
`)
|
|
260
|
-
.run(
|
|
261
|
-
|
|
373
|
+
.run(...insert.values);
|
|
374
|
+
}
|
|
375
|
+
function updateObservation(adapter, id, input, normalizedSourceLocator, contextColumns, contextKeys) {
|
|
376
|
+
const assignments = [
|
|
377
|
+
'entity_kind_hint = ?',
|
|
378
|
+
'surface_form = ?',
|
|
379
|
+
'normalized_form = ?',
|
|
380
|
+
'lang = ?',
|
|
381
|
+
'script = ?',
|
|
382
|
+
'context_summary = ?',
|
|
383
|
+
'related_surface_forms = ?',
|
|
384
|
+
'timestamp_observed = ?',
|
|
385
|
+
'scope_kind = ?',
|
|
386
|
+
'scope_id = ?',
|
|
387
|
+
'extractor_version = ?',
|
|
388
|
+
'embedding_model_version = ?',
|
|
389
|
+
'source_locator = ?',
|
|
390
|
+
...contextColumns.map((column) => `${column} = ?`),
|
|
391
|
+
];
|
|
392
|
+
const values = [
|
|
393
|
+
input.entity_kind_hint,
|
|
394
|
+
input.surface_form,
|
|
395
|
+
input.normalized_form,
|
|
396
|
+
input.lang,
|
|
397
|
+
input.script,
|
|
398
|
+
input.context_summary,
|
|
399
|
+
JSON.stringify(input.related_surface_forms),
|
|
400
|
+
input.timestamp_observed,
|
|
401
|
+
input.scope_kind,
|
|
402
|
+
input.scope_id,
|
|
403
|
+
input.extractor_version,
|
|
404
|
+
input.embedding_model_version,
|
|
405
|
+
normalizedSourceLocator,
|
|
406
|
+
...contextColumns.map((column) => contextKeys[column]),
|
|
407
|
+
id,
|
|
408
|
+
];
|
|
409
|
+
adapter
|
|
262
410
|
.prepare(`
|
|
263
|
-
|
|
264
|
-
|
|
411
|
+
UPDATE entity_observations
|
|
412
|
+
SET ${assignments.join(', ')}
|
|
413
|
+
WHERE id = ?
|
|
265
414
|
`)
|
|
266
|
-
.
|
|
415
|
+
.run(...values);
|
|
416
|
+
}
|
|
417
|
+
function saveObservation(adapter, input) {
|
|
418
|
+
const columns = tableColumnNames(adapter, 'entity_observations');
|
|
419
|
+
const contextColumns = observationContextColumns(columns);
|
|
420
|
+
const contextKeys = observationContextKeys(input);
|
|
421
|
+
const normalizedSourceLocator = sourceLocatorForInput(input);
|
|
422
|
+
const existing = findExistingObservation(adapter, input, normalizedSourceLocator, contextColumns, contextKeys);
|
|
423
|
+
if (existing) {
|
|
424
|
+
const id = requireStringField(existing, 'id');
|
|
425
|
+
updateObservation(adapter, id, input, normalizedSourceLocator, contextColumns, contextKeys);
|
|
426
|
+
return { id, created: false };
|
|
427
|
+
}
|
|
428
|
+
insertObservation(adapter, input, normalizedSourceLocator, contextColumns, contextKeys, now());
|
|
429
|
+
return { id: input.id, created: true };
|
|
430
|
+
}
|
|
431
|
+
async function upsertEntityObservation(input) {
|
|
432
|
+
await (0, db_manager_js_1.initDB)();
|
|
433
|
+
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
434
|
+
const result = saveObservation(adapter, input);
|
|
435
|
+
const saved = adapter.prepare('SELECT * FROM entity_observations WHERE id = ?').get(result.id);
|
|
436
|
+
if (!saved) {
|
|
437
|
+
throw new Error(`Failed to load saved entity observation ${result.id}`);
|
|
438
|
+
}
|
|
267
439
|
return parseObservationRow(saved);
|
|
268
440
|
}
|
|
269
441
|
async function upsertEntityObservations(inputs) {
|
|
@@ -271,51 +443,7 @@ async function upsertEntityObservations(inputs) {
|
|
|
271
443
|
const adapter = (0, db_manager_js_1.getAdapter)();
|
|
272
444
|
const observations = [];
|
|
273
445
|
const upsertOne = (input) => {
|
|
274
|
-
|
|
275
|
-
const existing = adapter
|
|
276
|
-
.prepare(`
|
|
277
|
-
SELECT id FROM entity_observations
|
|
278
|
-
WHERE source_connector = ? AND source_locator = ? AND source_raw_record_id = ? AND observation_type = ?
|
|
279
|
-
`)
|
|
280
|
-
.get(input.source_connector, normalizedSourceLocator, input.source_raw_record_id, input.observation_type);
|
|
281
|
-
const createdAt = now();
|
|
282
|
-
adapter
|
|
283
|
-
.prepare(`
|
|
284
|
-
INSERT INTO entity_observations (
|
|
285
|
-
id, observation_type, entity_kind_hint, surface_form, normalized_form, lang, script,
|
|
286
|
-
context_summary, related_surface_forms, timestamp_observed, scope_kind, scope_id,
|
|
287
|
-
extractor_version, embedding_model_version, source_connector, source_locator,
|
|
288
|
-
source_raw_record_id, created_at
|
|
289
|
-
)
|
|
290
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
291
|
-
ON CONFLICT(source_connector, source_locator, source_raw_record_id, observation_type)
|
|
292
|
-
DO UPDATE SET
|
|
293
|
-
entity_kind_hint = excluded.entity_kind_hint,
|
|
294
|
-
surface_form = excluded.surface_form,
|
|
295
|
-
normalized_form = excluded.normalized_form,
|
|
296
|
-
lang = excluded.lang,
|
|
297
|
-
script = excluded.script,
|
|
298
|
-
context_summary = excluded.context_summary,
|
|
299
|
-
related_surface_forms = excluded.related_surface_forms,
|
|
300
|
-
timestamp_observed = excluded.timestamp_observed,
|
|
301
|
-
scope_kind = excluded.scope_kind,
|
|
302
|
-
scope_id = excluded.scope_id,
|
|
303
|
-
extractor_version = excluded.extractor_version,
|
|
304
|
-
embedding_model_version = excluded.embedding_model_version,
|
|
305
|
-
source_locator = excluded.source_locator,
|
|
306
|
-
created_at = entity_observations.created_at
|
|
307
|
-
`)
|
|
308
|
-
.run(input.id, input.observation_type, input.entity_kind_hint, input.surface_form, input.normalized_form, input.lang, input.script, input.context_summary, JSON.stringify(input.related_surface_forms), input.timestamp_observed, input.scope_kind, input.scope_id, input.extractor_version, input.embedding_model_version, input.source_connector, normalizedSourceLocator, input.source_raw_record_id, createdAt);
|
|
309
|
-
const saved = adapter
|
|
310
|
-
.prepare(`
|
|
311
|
-
SELECT * FROM entity_observations
|
|
312
|
-
WHERE source_connector = ? AND source_locator = ? AND source_raw_record_id = ? AND observation_type = ?
|
|
313
|
-
`)
|
|
314
|
-
.get(input.source_connector, normalizedSourceLocator, input.source_raw_record_id, input.observation_type);
|
|
315
|
-
observations.push({
|
|
316
|
-
id: requireStringField(saved, 'id'),
|
|
317
|
-
created: !existing,
|
|
318
|
-
});
|
|
446
|
+
observations.push(saveObservation(adapter, input));
|
|
319
447
|
};
|
|
320
448
|
if ('transaction' in adapter && typeof adapter.transaction === 'function') {
|
|
321
449
|
const txResult = adapter.transaction(() => {
|
package/dist/entities/types.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare const ENTITY_NODE_STATUSES: readonly ["active", "merged", "archiv
|
|
|
12
12
|
export type EntityNodeStatus = (typeof ENTITY_NODE_STATUSES)[number];
|
|
13
13
|
export declare const ENTITY_ALIAS_STATUSES: readonly ["active", "suppressed"];
|
|
14
14
|
export type EntityAliasStatus = (typeof ENTITY_ALIAS_STATUSES)[number];
|
|
15
|
-
export declare const ENTITY_OBSERVATION_TYPES: readonly ["generic", "author", "channel"];
|
|
15
|
+
export declare const ENTITY_OBSERVATION_TYPES: readonly ["generic", "author", "channel", "thread"];
|
|
16
16
|
export type EntityObservationType = (typeof ENTITY_OBSERVATION_TYPES)[number];
|
|
17
17
|
export declare const ENTITY_CANDIDATE_KINDS: readonly ["alias_to_entity", "entity_to_entity", "cluster"];
|
|
18
18
|
export type EntityCandidateKind = (typeof ENTITY_CANDIDATE_KINDS)[number];
|
|
@@ -71,6 +71,10 @@ export interface EntityObservation {
|
|
|
71
71
|
source_connector: string;
|
|
72
72
|
source_locator: string | null;
|
|
73
73
|
source_raw_record_id: string;
|
|
74
|
+
workspace_context_key?: string | null;
|
|
75
|
+
channel_context_key?: string | null;
|
|
76
|
+
thread_context_key?: string | null;
|
|
77
|
+
actor_context_key?: string | null;
|
|
74
78
|
created_at: number;
|
|
75
79
|
}
|
|
76
80
|
export interface EntityResolutionCandidate {
|
package/dist/entities/types.js
CHANGED
|
@@ -14,7 +14,7 @@ exports.ENTITY_MERGE_ACTION_TYPES = ['merge', 'reject', 'defer', 'split'];
|
|
|
14
14
|
exports.ENTITY_SCOPE_KINDS = ['project', 'channel', 'user', 'global'];
|
|
15
15
|
exports.ENTITY_NODE_STATUSES = ['active', 'merged', 'archived'];
|
|
16
16
|
exports.ENTITY_ALIAS_STATUSES = ['active', 'suppressed'];
|
|
17
|
-
exports.ENTITY_OBSERVATION_TYPES = ['generic', 'author', 'channel'];
|
|
17
|
+
exports.ENTITY_OBSERVATION_TYPES = ['generic', 'author', 'channel', 'thread'];
|
|
18
18
|
exports.ENTITY_CANDIDATE_KINDS = ['alias_to_entity', 'entity_to_entity', 'cluster'];
|
|
19
19
|
exports.ENTITY_ACTOR_TYPES = ['system', 'user', 'agent'];
|
|
20
20
|
exports.ENTITY_INGEST_RUN_STATUSES = ['running', 'complete', 'failed'];
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export { appendToolTrace, listToolTracesForRun } from './model-runs/tool-trace-s
|
|
|
29
29
|
export { TWIN_EDGE_SOURCES, TWIN_EDGE_TYPES, TWIN_REF_KINDS, type InsertTwinEdgeInput, type ListVisibleTwinEdgesOptions, type TwinEdgeRecord, type TwinEdgeSource, type TwinEdgeType, type TwinRef, type TwinRefKind, type TwinScopeRef, } from './edges/types.js';
|
|
30
30
|
export { getTwinEdge, insertTwinEdge, listTwinEdgesForRefs, mapTwinEdgeRow, } from './edges/store.js';
|
|
31
31
|
export { assertTwinRefsVisibleToScopes, listVisibleTwinEdgesForRefs, } from './edges/ref-validation.js';
|
|
32
|
+
export * from './context-compile/index.js';
|
|
32
33
|
export * from './agent-situation/index.js';
|
|
33
34
|
export * from './agent-graph/index.js';
|
|
34
35
|
export * from './entities/types.js';
|
package/dist/index.js
CHANGED
|
@@ -150,6 +150,7 @@ Object.defineProperty(exports, "mapTwinEdgeRow", { enumerable: true, get: functi
|
|
|
150
150
|
var ref_validation_js_1 = require("./edges/ref-validation.js");
|
|
151
151
|
Object.defineProperty(exports, "assertTwinRefsVisibleToScopes", { enumerable: true, get: function () { return ref_validation_js_1.assertTwinRefsVisibleToScopes; } });
|
|
152
152
|
Object.defineProperty(exports, "listVisibleTwinEdgesForRefs", { enumerable: true, get: function () { return ref_validation_js_1.listVisibleTwinEdgesForRefs; } });
|
|
153
|
+
__exportStar(require("./context-compile/index.js"), exports);
|
|
153
154
|
__exportStar(require("./agent-situation/index.js"), exports);
|
|
154
155
|
__exportStar(require("./agent-graph/index.js"), exports);
|
|
155
156
|
__exportStar(require("./entities/types.js"), exports);
|
package/dist/memory/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jungjaehoon/mama-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "MAMA Core - Shared modules for Memory-Augmented MCP Assistant",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"./connectors/types": "./dist/connectors/types.js",
|
|
50
50
|
"./agent-situation": "./dist/agent-situation/index.js",
|
|
51
51
|
"./agent-graph": "./dist/agent-graph/index.js",
|
|
52
|
+
"./context-compile": "./dist/context-compile/index.js",
|
|
52
53
|
"./edges/types": "./dist/edges/types.js",
|
|
53
54
|
"./edges/store": "./dist/edges/store.js",
|
|
54
55
|
"./edges/ref-validation": "./dist/edges/ref-validation.js"
|
|
@@ -74,7 +75,7 @@
|
|
|
74
75
|
"license": "MIT",
|
|
75
76
|
"repository": {
|
|
76
77
|
"type": "git",
|
|
77
|
-
"url": "https://github.com/jungjaehoon-lifegamez/MAMA.git",
|
|
78
|
+
"url": "git+https://github.com/jungjaehoon-lifegamez/MAMA.git",
|
|
78
79
|
"directory": "packages/mama-core"
|
|
79
80
|
},
|
|
80
81
|
"bugs": {
|