@gethmy/mcp 2.3.2 → 2.3.3
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/dist/lib/api-client.js +1 -433
- package/dist/lib/config.js +0 -18
- package/package.json +9 -5
- package/dist/lib/active-learning.js +0 -974
- package/dist/lib/auto-session.js +0 -195
- package/dist/lib/cli.js +0 -34964
- package/dist/lib/consolidation.js +0 -388
- package/dist/lib/context-assembly.js +0 -1311
- package/dist/lib/graph-expansion.js +0 -147
- package/dist/lib/http.js +0 -1962
- package/dist/lib/index.js +0 -29527
- package/dist/lib/lifecycle-maintenance.js +0 -672
- package/dist/lib/memory-cleanup.js +0 -1361
- package/dist/lib/onboard.js +0 -2592
- package/dist/lib/prompt-builder.js +0 -481
- package/dist/lib/remote.js +0 -31756
- package/dist/lib/server.js +0 -29524
- package/dist/lib/skills.js +0 -776
- package/dist/lib/tui/agents.js +0 -137
- package/dist/lib/tui/docs.js +0 -1647
- package/dist/lib/tui/setup.js +0 -5828
- package/dist/lib/tui/theme.js +0 -192
- package/dist/lib/tui/writer.js +0 -1173
|
@@ -1,1311 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
19
|
-
var __export = (target, all) => {
|
|
20
|
-
for (var name in all)
|
|
21
|
-
__defProp(target, name, {
|
|
22
|
-
get: all[name],
|
|
23
|
-
enumerable: true,
|
|
24
|
-
configurable: true,
|
|
25
|
-
set: (newValue) => all[name] = () => newValue
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
29
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
|
-
|
|
31
|
-
// ../memory/dist/schema.js
|
|
32
|
-
var init_schema = () => {};
|
|
33
|
-
|
|
34
|
-
// ../memory/dist/constraints.js
|
|
35
|
-
var init_constraints = __esm(() => {
|
|
36
|
-
init_schema();
|
|
37
|
-
});
|
|
38
|
-
// ../memory/dist/client.js
|
|
39
|
-
var init_client = __esm(() => {
|
|
40
|
-
init_constraints();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// ../memory/dist/graph-walk.js
|
|
44
|
-
async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
45
|
-
const visited = new Set;
|
|
46
|
-
const collectedEntities = [];
|
|
47
|
-
const collectedRelations = [];
|
|
48
|
-
let truncated = false;
|
|
49
|
-
const queue = startIds.map((id) => [id, 0]);
|
|
50
|
-
for (const id of startIds) {
|
|
51
|
-
visited.add(id);
|
|
52
|
-
}
|
|
53
|
-
while (queue.length > 0) {
|
|
54
|
-
const [entityId, depth] = queue.shift();
|
|
55
|
-
if (collectedEntities.length >= maxEntities) {
|
|
56
|
-
truncated = true;
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
if (depth > maxDepth)
|
|
60
|
-
continue;
|
|
61
|
-
try {
|
|
62
|
-
const entityResult = await client.getMemoryEntity(entityId);
|
|
63
|
-
const entity = entityResult.entity;
|
|
64
|
-
if (entity) {
|
|
65
|
-
collectedEntities.push({
|
|
66
|
-
id: entity.id,
|
|
67
|
-
type: entity.type,
|
|
68
|
-
title: entity.title,
|
|
69
|
-
confidence: entity.confidence ?? 1,
|
|
70
|
-
memory_tier: entity.memory_tier || "reference"
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
if (depth >= maxDepth)
|
|
74
|
-
continue;
|
|
75
|
-
const related = await client.getRelatedEntities(entityId);
|
|
76
|
-
for (const raw of related.outgoing || []) {
|
|
77
|
-
const rel = raw;
|
|
78
|
-
const relConfidence = rel.confidence ?? 1;
|
|
79
|
-
if (relConfidence < minConfidence)
|
|
80
|
-
continue;
|
|
81
|
-
const target = rel.target;
|
|
82
|
-
const targetId = target?.id ?? rel.target_id;
|
|
83
|
-
if (targetId && !visited.has(targetId)) {
|
|
84
|
-
visited.add(targetId);
|
|
85
|
-
queue.push([targetId, depth + 1]);
|
|
86
|
-
collectedRelations.push({
|
|
87
|
-
id: rel.id,
|
|
88
|
-
source_id: entityId,
|
|
89
|
-
target_id: targetId,
|
|
90
|
-
relation_type: rel.relation_type,
|
|
91
|
-
confidence: relConfidence
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
for (const raw of related.incoming || []) {
|
|
96
|
-
const rel = raw;
|
|
97
|
-
const relConfidence = rel.confidence ?? 1;
|
|
98
|
-
if (relConfidence < minConfidence)
|
|
99
|
-
continue;
|
|
100
|
-
const source = rel.source;
|
|
101
|
-
const sourceId = source?.id ?? rel.source_id;
|
|
102
|
-
if (sourceId && !visited.has(sourceId)) {
|
|
103
|
-
visited.add(sourceId);
|
|
104
|
-
queue.push([sourceId, depth + 1]);
|
|
105
|
-
collectedRelations.push({
|
|
106
|
-
id: rel.id,
|
|
107
|
-
source_id: sourceId,
|
|
108
|
-
target_id: entityId,
|
|
109
|
-
relation_type: rel.relation_type,
|
|
110
|
-
confidence: relConfidence
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} catch {}
|
|
115
|
-
}
|
|
116
|
-
return {
|
|
117
|
-
entities: collectedEntities,
|
|
118
|
-
relations: collectedRelations,
|
|
119
|
-
depth: maxDepth,
|
|
120
|
-
truncated
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// ../memory/dist/lifecycle.js
|
|
125
|
-
function computeDecayScore(tier, lastAccessedAt, accessCount) {
|
|
126
|
-
const halfLife = DECAY_HALF_LIVES[tier];
|
|
127
|
-
const now = Date.now();
|
|
128
|
-
let daysSinceAccess = 0;
|
|
129
|
-
if (lastAccessedAt) {
|
|
130
|
-
daysSinceAccess = (now - new Date(lastAccessedAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
131
|
-
}
|
|
132
|
-
const timeDecay = 0.5 ** (daysSinceAccess / halfLife);
|
|
133
|
-
const accessBonus = Math.log10(accessCount + 1) * 0.1;
|
|
134
|
-
const score = Math.min(timeDecay + accessBonus, 1);
|
|
135
|
-
return { score, daysSinceAccess, halfLife, accessBonus };
|
|
136
|
-
}
|
|
137
|
-
function checkPromotion(currentTier, accessCount, confidence, createdAt) {
|
|
138
|
-
const ageDays = (Date.now() - new Date(createdAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
139
|
-
const base = {
|
|
140
|
-
eligible: false,
|
|
141
|
-
targetTier: null,
|
|
142
|
-
reason: null,
|
|
143
|
-
currentTier,
|
|
144
|
-
accessCount,
|
|
145
|
-
confidence,
|
|
146
|
-
ageDays
|
|
147
|
-
};
|
|
148
|
-
if (currentTier === "draft") {
|
|
149
|
-
const rules = PROMOTION_RULES.draftToEpisode;
|
|
150
|
-
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
151
|
-
return {
|
|
152
|
-
...base,
|
|
153
|
-
eligible: true,
|
|
154
|
-
targetTier: "episode",
|
|
155
|
-
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (currentTier === "episode") {
|
|
160
|
-
const rules = PROMOTION_RULES.episodeToReference;
|
|
161
|
-
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
162
|
-
return {
|
|
163
|
-
...base,
|
|
164
|
-
eligible: true,
|
|
165
|
-
targetTier: "reference",
|
|
166
|
-
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return base;
|
|
171
|
-
}
|
|
172
|
-
function evaluateLifecycle(entity) {
|
|
173
|
-
const decay = computeDecayScore(entity.memory_tier, entity.last_accessed_at, entity.access_count);
|
|
174
|
-
const promotion = checkPromotion(entity.memory_tier, entity.access_count, entity.confidence, entity.created_at);
|
|
175
|
-
const shouldArchive = entity.confidence < ARCHIVE_THRESHOLD;
|
|
176
|
-
const archiveReason = shouldArchive ? `Confidence ${entity.confidence} below threshold ${ARCHIVE_THRESHOLD}` : undefined;
|
|
177
|
-
const shouldFlagForReview = decay.daysSinceAccess >= STALE_DAYS && entity.access_count < STALE_MIN_ACCESS;
|
|
178
|
-
const reviewReason = shouldFlagForReview ? `Not accessed in ${Math.round(decay.daysSinceAccess)} days with only ${entity.access_count} accesses` : undefined;
|
|
179
|
-
return {
|
|
180
|
-
decay,
|
|
181
|
-
promotion,
|
|
182
|
-
shouldArchive,
|
|
183
|
-
shouldFlagForReview,
|
|
184
|
-
archiveReason,
|
|
185
|
-
reviewReason
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
var DECAY_HALF_LIVES, PROMOTION_RULES, ARCHIVE_THRESHOLD = 0.3, STALE_DAYS = 90, STALE_MIN_ACCESS = 3;
|
|
189
|
-
var init_lifecycle = __esm(() => {
|
|
190
|
-
DECAY_HALF_LIVES = {
|
|
191
|
-
draft: 7,
|
|
192
|
-
episode: 30,
|
|
193
|
-
reference: 180
|
|
194
|
-
};
|
|
195
|
-
PROMOTION_RULES = {
|
|
196
|
-
draftToEpisode: {
|
|
197
|
-
minAccessCount: 5,
|
|
198
|
-
minConfidence: 0.8,
|
|
199
|
-
minAgeDays: 1
|
|
200
|
-
},
|
|
201
|
-
episodeToReference: {
|
|
202
|
-
minAccessCount: 10,
|
|
203
|
-
minConfidence: 0.9,
|
|
204
|
-
minAgeDays: 7
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// ../memory/dist/sync-storage.js
|
|
210
|
-
function parseSyncMarkdown(markdown) {
|
|
211
|
-
const trimmed = markdown.trim();
|
|
212
|
-
let frontmatter = {
|
|
213
|
-
type: "context",
|
|
214
|
-
scope: "project",
|
|
215
|
-
tier: "reference",
|
|
216
|
-
confidence: 1,
|
|
217
|
-
tags: []
|
|
218
|
-
};
|
|
219
|
-
let body = trimmed;
|
|
220
|
-
const fmMatch = trimmed.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
221
|
-
if (fmMatch) {
|
|
222
|
-
frontmatter = parseSyncYamlFrontmatter(fmMatch[1]);
|
|
223
|
-
body = fmMatch[2].trim();
|
|
224
|
-
}
|
|
225
|
-
let title = "";
|
|
226
|
-
const titleMatch = body.match(/^#\s+(.+)/m);
|
|
227
|
-
if (titleMatch) {
|
|
228
|
-
title = titleMatch[1].trim();
|
|
229
|
-
body = body.replace(/^#\s+.+\n?/, "").trim();
|
|
230
|
-
}
|
|
231
|
-
return { frontmatter, title, content: body };
|
|
232
|
-
}
|
|
233
|
-
function serializeSyncMarkdown(entity) {
|
|
234
|
-
const lines = ["---"];
|
|
235
|
-
lines.push(`id: ${entity.id}`);
|
|
236
|
-
lines.push(`workspace_id: ${entity.workspace_id}`);
|
|
237
|
-
if (entity.project_id) {
|
|
238
|
-
lines.push(`project_id: ${entity.project_id}`);
|
|
239
|
-
}
|
|
240
|
-
lines.push(`type: ${entity.type}`);
|
|
241
|
-
lines.push(`scope: ${entity.scope}`);
|
|
242
|
-
lines.push(`tier: ${entity.memory_tier || "reference"}`);
|
|
243
|
-
lines.push(`confidence: ${entity.confidence}`);
|
|
244
|
-
if (entity.tags.length > 0) {
|
|
245
|
-
lines.push(`tags: [${entity.tags.join(", ")}]`);
|
|
246
|
-
} else {
|
|
247
|
-
lines.push("tags: []");
|
|
248
|
-
}
|
|
249
|
-
if (entity.agent_identifier) {
|
|
250
|
-
lines.push(`agent: ${entity.agent_identifier}`);
|
|
251
|
-
}
|
|
252
|
-
lines.push(`created_at: ${entity.created_at}`);
|
|
253
|
-
lines.push(`updated_at: ${entity.updated_at}`);
|
|
254
|
-
lines.push("---");
|
|
255
|
-
lines.push("");
|
|
256
|
-
lines.push(`# ${entity.title}`);
|
|
257
|
-
lines.push("");
|
|
258
|
-
lines.push(entity.content);
|
|
259
|
-
return lines.join(`
|
|
260
|
-
`);
|
|
261
|
-
}
|
|
262
|
-
function parseSyncYamlFrontmatter(yaml) {
|
|
263
|
-
const result = {
|
|
264
|
-
type: "context",
|
|
265
|
-
scope: "project",
|
|
266
|
-
tier: "reference",
|
|
267
|
-
confidence: 1,
|
|
268
|
-
tags: []
|
|
269
|
-
};
|
|
270
|
-
for (const line of yaml.split(`
|
|
271
|
-
`)) {
|
|
272
|
-
const colonIndex = line.indexOf(":");
|
|
273
|
-
if (colonIndex === -1)
|
|
274
|
-
continue;
|
|
275
|
-
const key = line.slice(0, colonIndex).trim();
|
|
276
|
-
const value = line.slice(colonIndex + 1).trim();
|
|
277
|
-
switch (key) {
|
|
278
|
-
case "id":
|
|
279
|
-
result.id = value;
|
|
280
|
-
break;
|
|
281
|
-
case "workspace_id":
|
|
282
|
-
result.workspace_id = value;
|
|
283
|
-
break;
|
|
284
|
-
case "project_id":
|
|
285
|
-
result.project_id = value;
|
|
286
|
-
break;
|
|
287
|
-
case "type":
|
|
288
|
-
result.type = value;
|
|
289
|
-
break;
|
|
290
|
-
case "scope":
|
|
291
|
-
result.scope = value;
|
|
292
|
-
break;
|
|
293
|
-
case "tier":
|
|
294
|
-
result.tier = value;
|
|
295
|
-
break;
|
|
296
|
-
case "confidence":
|
|
297
|
-
result.confidence = parseFloat(value) || 1;
|
|
298
|
-
break;
|
|
299
|
-
case "tags":
|
|
300
|
-
result.tags = parseYamlArray(value);
|
|
301
|
-
break;
|
|
302
|
-
case "related":
|
|
303
|
-
result.related = parseYamlArray(value);
|
|
304
|
-
break;
|
|
305
|
-
case "agent":
|
|
306
|
-
result.agent = value;
|
|
307
|
-
break;
|
|
308
|
-
case "created_at":
|
|
309
|
-
result.created_at = value;
|
|
310
|
-
break;
|
|
311
|
-
case "updated_at":
|
|
312
|
-
result.updated_at = value;
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return result;
|
|
317
|
-
}
|
|
318
|
-
function parseYamlArray(value) {
|
|
319
|
-
const match = value.match(/^\[(.*)]\s*$/);
|
|
320
|
-
if (!match)
|
|
321
|
-
return [];
|
|
322
|
-
return match[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// ../memory/dist/sync.js
|
|
326
|
-
import { createHash } from "node:crypto";
|
|
327
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
328
|
-
import { join, relative, sep } from "node:path";
|
|
329
|
-
function computeFileHash(content) {
|
|
330
|
-
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
331
|
-
}
|
|
332
|
-
function slugifyTitle(title) {
|
|
333
|
-
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
334
|
-
}
|
|
335
|
-
function entityToFilename(entity) {
|
|
336
|
-
const slug = slugifyTitle(entity.title);
|
|
337
|
-
const shortId = entity.id.slice(0, 8);
|
|
338
|
-
return `${entity.type}--${slug}--${shortId}.md`;
|
|
339
|
-
}
|
|
340
|
-
function entityToDirectoryPath(entity, memoryDir) {
|
|
341
|
-
const wsDir = join(memoryDir, entity.workspace_id);
|
|
342
|
-
if (entity.scope === "private") {
|
|
343
|
-
return join(wsDir, "_private");
|
|
344
|
-
}
|
|
345
|
-
if (entity.scope === "workspace" || !entity.project_id) {
|
|
346
|
-
return join(wsDir, "_workspace");
|
|
347
|
-
}
|
|
348
|
-
return join(wsDir, entity.project_id);
|
|
349
|
-
}
|
|
350
|
-
function emptySyncState() {
|
|
351
|
-
return { version: 1, lastPullAt: null, entities: {} };
|
|
352
|
-
}
|
|
353
|
-
function loadSyncState(memoryDir) {
|
|
354
|
-
const statePath = join(memoryDir, ".sync-state.json");
|
|
355
|
-
if (!existsSync(statePath))
|
|
356
|
-
return emptySyncState();
|
|
357
|
-
try {
|
|
358
|
-
return JSON.parse(readFileSync(statePath, "utf-8"));
|
|
359
|
-
} catch {
|
|
360
|
-
return emptySyncState();
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
function saveSyncState(memoryDir, state) {
|
|
364
|
-
if (!existsSync(memoryDir)) {
|
|
365
|
-
mkdirSync(memoryDir, { recursive: true });
|
|
366
|
-
}
|
|
367
|
-
writeFileSync(join(memoryDir, ".sync-state.json"), JSON.stringify(state, null, 2));
|
|
368
|
-
}
|
|
369
|
-
function writeEntityFile(entity, memoryDir) {
|
|
370
|
-
const dir = entityToDirectoryPath(entity, memoryDir);
|
|
371
|
-
if (!existsSync(dir))
|
|
372
|
-
mkdirSync(dir, { recursive: true });
|
|
373
|
-
const filename = entityToFilename(entity);
|
|
374
|
-
const filePath = join(dir, filename);
|
|
375
|
-
const markdown = serializeSyncMarkdown(entity);
|
|
376
|
-
writeFileSync(filePath, markdown);
|
|
377
|
-
return relative(memoryDir, filePath);
|
|
378
|
-
}
|
|
379
|
-
function deleteEntityFile(relPath, memoryDir) {
|
|
380
|
-
const absPath = join(memoryDir, relPath);
|
|
381
|
-
if (existsSync(absPath)) {
|
|
382
|
-
rmSync(absPath);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
function findMarkdownFiles(dir) {
|
|
386
|
-
const results = [];
|
|
387
|
-
if (!existsSync(dir))
|
|
388
|
-
return results;
|
|
389
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
390
|
-
const fullPath = join(dir, entry.name);
|
|
391
|
-
if (entry.isDirectory()) {
|
|
392
|
-
results.push(...findMarkdownFiles(fullPath));
|
|
393
|
-
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
394
|
-
results.push(fullPath);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
return results;
|
|
398
|
-
}
|
|
399
|
-
async function syncPull(client, config, workspaceId, projectId) {
|
|
400
|
-
const { memoryDir } = config;
|
|
401
|
-
const state = loadSyncState(memoryDir);
|
|
402
|
-
const result = {
|
|
403
|
-
pulled: 0,
|
|
404
|
-
pushed: 0,
|
|
405
|
-
deleted: 0,
|
|
406
|
-
conflicts: 0,
|
|
407
|
-
errors: []
|
|
408
|
-
};
|
|
409
|
-
const allEntities = [];
|
|
410
|
-
let offset = 0;
|
|
411
|
-
const batchSize = 100;
|
|
412
|
-
while (true) {
|
|
413
|
-
try {
|
|
414
|
-
const resp = await client.listMemoryEntities({
|
|
415
|
-
workspace_id: workspaceId,
|
|
416
|
-
project_id: projectId,
|
|
417
|
-
limit: batchSize,
|
|
418
|
-
offset
|
|
419
|
-
});
|
|
420
|
-
const batch = resp.entities;
|
|
421
|
-
allEntities.push(...batch);
|
|
422
|
-
if (batch.length < batchSize)
|
|
423
|
-
break;
|
|
424
|
-
offset += batchSize;
|
|
425
|
-
} catch (err) {
|
|
426
|
-
result.errors.push(`Failed to fetch entities: ${err}`);
|
|
427
|
-
return result;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
const remoteIds = new Set(allEntities.map((e) => e.id));
|
|
431
|
-
for (const entity of allEntities) {
|
|
432
|
-
const existing = state.entities[entity.id];
|
|
433
|
-
const markdown = serializeSyncMarkdown(entity);
|
|
434
|
-
const hash = computeFileHash(markdown);
|
|
435
|
-
if (!existing) {
|
|
436
|
-
const relPath = writeEntityFile(entity, memoryDir);
|
|
437
|
-
state.entities[entity.id] = {
|
|
438
|
-
filePath: relPath,
|
|
439
|
-
remoteUpdatedAt: entity.updated_at,
|
|
440
|
-
lastSyncedHash: hash
|
|
441
|
-
};
|
|
442
|
-
result.pulled++;
|
|
443
|
-
} else {
|
|
444
|
-
const remoteChanged = entity.updated_at > existing.remoteUpdatedAt;
|
|
445
|
-
if (!remoteChanged)
|
|
446
|
-
continue;
|
|
447
|
-
const absPath = join(memoryDir, existing.filePath);
|
|
448
|
-
let localChanged = false;
|
|
449
|
-
if (existsSync(absPath)) {
|
|
450
|
-
const localContent = readFileSync(absPath, "utf-8");
|
|
451
|
-
const localHash = computeFileHash(localContent);
|
|
452
|
-
localChanged = localHash !== existing.lastSyncedHash;
|
|
453
|
-
}
|
|
454
|
-
if (localChanged) {
|
|
455
|
-
result.conflicts++;
|
|
456
|
-
}
|
|
457
|
-
const newRelPath = writeEntityFile(entity, memoryDir);
|
|
458
|
-
if (existing.filePath !== newRelPath) {
|
|
459
|
-
deleteEntityFile(existing.filePath, memoryDir);
|
|
460
|
-
}
|
|
461
|
-
state.entities[entity.id] = {
|
|
462
|
-
filePath: newRelPath,
|
|
463
|
-
remoteUpdatedAt: entity.updated_at,
|
|
464
|
-
lastSyncedHash: hash
|
|
465
|
-
};
|
|
466
|
-
result.pulled++;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
for (const [entityId, entry] of Object.entries(state.entities)) {
|
|
470
|
-
if (!remoteIds.has(entityId)) {
|
|
471
|
-
deleteEntityFile(entry.filePath, memoryDir);
|
|
472
|
-
delete state.entities[entityId];
|
|
473
|
-
result.deleted++;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
state.lastPullAt = new Date().toISOString();
|
|
477
|
-
saveSyncState(memoryDir, state);
|
|
478
|
-
return result;
|
|
479
|
-
}
|
|
480
|
-
async function syncPush(client, config, workspaceId) {
|
|
481
|
-
const { memoryDir } = config;
|
|
482
|
-
const state = loadSyncState(memoryDir);
|
|
483
|
-
const result = {
|
|
484
|
-
pulled: 0,
|
|
485
|
-
pushed: 0,
|
|
486
|
-
deleted: 0,
|
|
487
|
-
conflicts: 0,
|
|
488
|
-
errors: []
|
|
489
|
-
};
|
|
490
|
-
const mdFiles = findMarkdownFiles(memoryDir);
|
|
491
|
-
for (const absPath of mdFiles) {
|
|
492
|
-
const content = readFileSync(absPath, "utf-8");
|
|
493
|
-
const hash = computeFileHash(content);
|
|
494
|
-
const parsed = parseSyncMarkdown(content);
|
|
495
|
-
if (parsed.frontmatter.id) {
|
|
496
|
-
const entityId = parsed.frontmatter.id;
|
|
497
|
-
const existing = state.entities[entityId];
|
|
498
|
-
if (existing && hash === existing.lastSyncedHash)
|
|
499
|
-
continue;
|
|
500
|
-
try {
|
|
501
|
-
const resp = await client.updateMemoryEntity(entityId, {
|
|
502
|
-
title: parsed.title || "Untitled",
|
|
503
|
-
content: parsed.content,
|
|
504
|
-
type: parsed.frontmatter.type,
|
|
505
|
-
scope: parsed.frontmatter.scope,
|
|
506
|
-
confidence: parsed.frontmatter.confidence,
|
|
507
|
-
tags: parsed.frontmatter.tags
|
|
508
|
-
});
|
|
509
|
-
const updated = resp.entity;
|
|
510
|
-
const newMarkdown = serializeSyncMarkdown(updated);
|
|
511
|
-
writeFileSync(absPath, newMarkdown);
|
|
512
|
-
const relPath = relative(memoryDir, absPath);
|
|
513
|
-
state.entities[entityId] = {
|
|
514
|
-
filePath: relPath,
|
|
515
|
-
remoteUpdatedAt: updated.updated_at,
|
|
516
|
-
lastSyncedHash: computeFileHash(newMarkdown)
|
|
517
|
-
};
|
|
518
|
-
result.pushed++;
|
|
519
|
-
} catch (err) {
|
|
520
|
-
result.errors.push(`Failed to update ${entityId}: ${err}`);
|
|
521
|
-
}
|
|
522
|
-
} else {
|
|
523
|
-
const relPath = relative(memoryDir, absPath);
|
|
524
|
-
const parts = relPath.split(sep);
|
|
525
|
-
const fileWorkspaceId = parts.length >= 2 ? parts[0] : workspaceId;
|
|
526
|
-
let fileProjectId;
|
|
527
|
-
if (parts.length >= 3) {
|
|
528
|
-
const scopeDir = parts[1];
|
|
529
|
-
if (scopeDir !== "_workspace" && scopeDir !== "_private") {
|
|
530
|
-
fileProjectId = scopeDir;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
let scope = parsed.frontmatter.scope || "project";
|
|
534
|
-
if (parts.length >= 3) {
|
|
535
|
-
const scopeDir = parts[1];
|
|
536
|
-
if (scopeDir === "_private")
|
|
537
|
-
scope = "private";
|
|
538
|
-
else if (scopeDir === "_workspace")
|
|
539
|
-
scope = "workspace";
|
|
540
|
-
}
|
|
541
|
-
try {
|
|
542
|
-
const resp = await client.createMemoryEntity({
|
|
543
|
-
workspace_id: fileWorkspaceId,
|
|
544
|
-
project_id: fileProjectId,
|
|
545
|
-
type: parsed.frontmatter.type,
|
|
546
|
-
scope,
|
|
547
|
-
title: parsed.title || "Untitled",
|
|
548
|
-
content: parsed.content,
|
|
549
|
-
confidence: parsed.frontmatter.confidence,
|
|
550
|
-
tags: parsed.frontmatter.tags,
|
|
551
|
-
agent_identifier: parsed.frontmatter.agent
|
|
552
|
-
});
|
|
553
|
-
const created = resp.entity;
|
|
554
|
-
const dir = entityToDirectoryPath(created, memoryDir);
|
|
555
|
-
if (!existsSync(dir))
|
|
556
|
-
mkdirSync(dir, { recursive: true });
|
|
557
|
-
const newFilename = entityToFilename(created);
|
|
558
|
-
const newAbsPath = join(dir, newFilename);
|
|
559
|
-
const newMarkdown = serializeSyncMarkdown(created);
|
|
560
|
-
writeFileSync(newAbsPath, newMarkdown);
|
|
561
|
-
if (absPath !== newAbsPath && existsSync(absPath)) {
|
|
562
|
-
rmSync(absPath);
|
|
563
|
-
}
|
|
564
|
-
const newRelPath = relative(memoryDir, newAbsPath);
|
|
565
|
-
state.entities[created.id] = {
|
|
566
|
-
filePath: newRelPath,
|
|
567
|
-
remoteUpdatedAt: created.updated_at,
|
|
568
|
-
lastSyncedHash: computeFileHash(newMarkdown)
|
|
569
|
-
};
|
|
570
|
-
result.pushed++;
|
|
571
|
-
} catch (err) {
|
|
572
|
-
result.errors.push(`Failed to create entity from ${relPath}: ${err}`);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
saveSyncState(memoryDir, state);
|
|
577
|
-
return result;
|
|
578
|
-
}
|
|
579
|
-
async function syncFull(client, config, workspaceId, projectId) {
|
|
580
|
-
const pullResult = await syncPull(client, config, workspaceId, projectId);
|
|
581
|
-
const pushResult = await syncPush(client, config, workspaceId);
|
|
582
|
-
return {
|
|
583
|
-
pulled: pullResult.pulled,
|
|
584
|
-
pushed: pushResult.pushed,
|
|
585
|
-
deleted: pullResult.deleted,
|
|
586
|
-
conflicts: pullResult.conflicts,
|
|
587
|
-
errors: [...pullResult.errors, ...pushResult.errors]
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
var init_sync = () => {};
|
|
591
|
-
|
|
592
|
-
// ../memory/dist/index.js
|
|
593
|
-
var init_dist = __esm(() => {
|
|
594
|
-
init_client();
|
|
595
|
-
init_constraints();
|
|
596
|
-
init_lifecycle();
|
|
597
|
-
init_schema();
|
|
598
|
-
init_sync();
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
// src/context-assembly.ts
|
|
602
|
-
var exports_context_assembly = {};
|
|
603
|
-
__export(exports_context_assembly, {
|
|
604
|
-
trackSessionAssembly: () => trackSessionAssembly,
|
|
605
|
-
recordContextFeedback: () => recordContextFeedback,
|
|
606
|
-
mapToContextEntity: () => mapToContextEntity,
|
|
607
|
-
getSessionAssemblyId: () => getSessionAssemblyId,
|
|
608
|
-
getCachedManifest: () => getCachedManifest,
|
|
609
|
-
expandQuery: () => expandQuery,
|
|
610
|
-
computeRelevanceScore: () => computeRelevanceScore,
|
|
611
|
-
cacheManifest: () => cacheManifest,
|
|
612
|
-
assembleContext: () => assembleContext
|
|
613
|
-
});
|
|
614
|
-
function estimateTokens(text) {
|
|
615
|
-
return Math.ceil(text.length / 4);
|
|
616
|
-
}
|
|
617
|
-
function passesQualityGate(entity) {
|
|
618
|
-
const content = entity.content.trim();
|
|
619
|
-
if (content.length < 50)
|
|
620
|
-
return false;
|
|
621
|
-
const normalizedTitle = entity.title.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim();
|
|
622
|
-
const normalizedContent = content.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim();
|
|
623
|
-
if (normalizedContent.length < normalizedTitle.length * 1.5) {
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
if (entity.type === "pattern" && /recurring .+ \(\d+ instances\)/i.test(entity.title)) {
|
|
627
|
-
const lines = content.split(`
|
|
628
|
-
`).filter((l) => l.trim().length > 0);
|
|
629
|
-
const bulletLines = lines.filter((l) => l.trim().startsWith("- "));
|
|
630
|
-
if (bulletLines.length > lines.length * 0.6)
|
|
631
|
-
return false;
|
|
632
|
-
}
|
|
633
|
-
if (entity.type === "procedure") {
|
|
634
|
-
const stepCount = (content.match(/^\d+\.\s/gm) || []).length;
|
|
635
|
-
if (stepCount < 3)
|
|
636
|
-
return false;
|
|
637
|
-
}
|
|
638
|
-
return true;
|
|
639
|
-
}
|
|
640
|
-
function generateAssemblyId() {
|
|
641
|
-
return `ctx_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
642
|
-
}
|
|
643
|
-
function truncateContent(content, maxTokens) {
|
|
644
|
-
const currentTokens = estimateTokens(content);
|
|
645
|
-
if (currentTokens <= maxTokens) {
|
|
646
|
-
return { text: content, truncated: false };
|
|
647
|
-
}
|
|
648
|
-
const paragraphs = content.split(/\n\n+/);
|
|
649
|
-
let result = paragraphs[0];
|
|
650
|
-
for (let i = 1;i < paragraphs.length; i++) {
|
|
651
|
-
const lines = paragraphs[i].split(`
|
|
652
|
-
`).filter((l) => l.startsWith("- ") || l.startsWith("* "));
|
|
653
|
-
if (lines.length > 0) {
|
|
654
|
-
const bulletSection = lines.join(`
|
|
655
|
-
`);
|
|
656
|
-
if (estimateTokens(result + `
|
|
657
|
-
|
|
658
|
-
` + bulletSection) <= maxTokens) {
|
|
659
|
-
result += `
|
|
660
|
-
|
|
661
|
-
` + bulletSection;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
if (estimateTokens(result) > maxTokens) {
|
|
666
|
-
const maxChars = maxTokens * 4;
|
|
667
|
-
result = result.slice(0, maxChars - 3) + "...";
|
|
668
|
-
}
|
|
669
|
-
return { text: result, truncated: true };
|
|
670
|
-
}
|
|
671
|
-
function escapeRegex(str) {
|
|
672
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
673
|
-
}
|
|
674
|
-
function expandQuery(taskContext) {
|
|
675
|
-
const queries = [taskContext];
|
|
676
|
-
const lowerQueries = [taskContext.toLowerCase()];
|
|
677
|
-
const words = taskContext.toLowerCase().split(/\W+/).filter((w) => w.length > 2);
|
|
678
|
-
const expandableWords = words.filter((w) => QUERY_SYNONYMS[w]);
|
|
679
|
-
for (const word of expandableWords) {
|
|
680
|
-
const synonyms = QUERY_SYNONYMS[word];
|
|
681
|
-
if (!synonyms)
|
|
682
|
-
continue;
|
|
683
|
-
const variation = taskContext.replace(new RegExp(`\\b${escapeRegex(word)}\\b`, "gi"), synonyms[0]);
|
|
684
|
-
const lowerVariation = variation.toLowerCase();
|
|
685
|
-
if (lowerVariation !== taskContext.toLowerCase() && !lowerQueries.includes(lowerVariation)) {
|
|
686
|
-
queries.push(variation);
|
|
687
|
-
lowerQueries.push(lowerVariation);
|
|
688
|
-
}
|
|
689
|
-
if (queries.length >= MAX_QUERY_VARIATIONS)
|
|
690
|
-
break;
|
|
691
|
-
}
|
|
692
|
-
if (words.length >= 3) {
|
|
693
|
-
const keyPhrases = words.filter((w) => ![
|
|
694
|
-
"the",
|
|
695
|
-
"and",
|
|
696
|
-
"for",
|
|
697
|
-
"with",
|
|
698
|
-
"this",
|
|
699
|
-
"that",
|
|
700
|
-
"from",
|
|
701
|
-
"into"
|
|
702
|
-
].includes(w)).slice(0, 4).join(" ");
|
|
703
|
-
if (!lowerQueries.includes(keyPhrases)) {
|
|
704
|
-
queries.push(keyPhrases);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
return queries.slice(0, MAX_QUERY_VARIATIONS);
|
|
708
|
-
}
|
|
709
|
-
function computeRelevanceScore(entity, taskContext, cardLabels, graphRelations) {
|
|
710
|
-
const reasons = [];
|
|
711
|
-
let score = 0;
|
|
712
|
-
const hasRrfScore = entity.rrf_score !== undefined && entity.rrf_score > 0;
|
|
713
|
-
if (hasRrfScore) {
|
|
714
|
-
const normalizedRrf = Math.min(entity.rrf_score / 0.04, 1);
|
|
715
|
-
const rrfContribution = normalizedRrf * 0.3;
|
|
716
|
-
score += rrfContribution;
|
|
717
|
-
reasons.push(`hybrid_search(rrf=${entity.rrf_score.toFixed(4)})`);
|
|
718
|
-
}
|
|
719
|
-
const textMatchWeight = hasRrfScore ? 0.15 : 0.4;
|
|
720
|
-
const taskWords = new Set(taskContext.toLowerCase().split(/\W+/).filter((w) => w.length > 2));
|
|
721
|
-
const entityWords = new Set(`${entity.title} ${entity.content}`.toLowerCase().split(/\W+/).filter((w) => w.length > 2));
|
|
722
|
-
const overlap = [...taskWords].filter((w) => entityWords.has(w));
|
|
723
|
-
if (overlap.length > 0) {
|
|
724
|
-
const textScore = Math.min(overlap.length / Math.max(taskWords.size, 1), 1) * textMatchWeight;
|
|
725
|
-
score += textScore;
|
|
726
|
-
reasons.push(`text_match(${overlap.length} words)`);
|
|
727
|
-
}
|
|
728
|
-
if (cardLabels.length > 0 && entity.tags.length > 0) {
|
|
729
|
-
const labelSet = new Set(cardLabels.map((l) => l.toLowerCase()));
|
|
730
|
-
const tagOverlap = entity.tags.filter((t) => labelSet.has(t.toLowerCase()));
|
|
731
|
-
if (tagOverlap.length > 0) {
|
|
732
|
-
const tagScore = tagOverlap.length / cardLabels.length * 0.3;
|
|
733
|
-
score += tagScore;
|
|
734
|
-
reasons.push(`tag_match(${tagOverlap.join(",")})`);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
score += entity.confidence * 0.15;
|
|
738
|
-
if (entity.confidence >= 0.9) {
|
|
739
|
-
reasons.push("high_confidence");
|
|
740
|
-
}
|
|
741
|
-
if (entity.last_accessed_at) {
|
|
742
|
-
const daysSinceAccess = (Date.now() - new Date(entity.last_accessed_at).getTime()) / (1000 * 60 * 60 * 24);
|
|
743
|
-
const halfLife = { draft: 7, episode: 30, reference: 180 }[entity.memory_tier];
|
|
744
|
-
const recencyScore = 0.5 ** (daysSinceAccess / halfLife) * 0.1;
|
|
745
|
-
score += recencyScore;
|
|
746
|
-
if (daysSinceAccess < 7)
|
|
747
|
-
reasons.push("recently_accessed");
|
|
748
|
-
}
|
|
749
|
-
if (entity.access_count > 0) {
|
|
750
|
-
const freqScore = Math.log10(entity.access_count + 1) * 0.05;
|
|
751
|
-
score += Math.min(freqScore, 0.1);
|
|
752
|
-
if (entity.access_count >= 5)
|
|
753
|
-
reasons.push(`frequently_used(${entity.access_count})`);
|
|
754
|
-
}
|
|
755
|
-
const usefulnessScore = entity.metadata?.usefulness_score ?? 0;
|
|
756
|
-
if (usefulnessScore >= 3) {
|
|
757
|
-
const usefulnessBoost = Math.min(usefulnessScore / 20, 0.15);
|
|
758
|
-
score += usefulnessBoost;
|
|
759
|
-
reasons.push(`useful(${usefulnessScore})`);
|
|
760
|
-
} else if (usefulnessScore === 0 && entity.access_count >= 5) {
|
|
761
|
-
score -= 0.02;
|
|
762
|
-
reasons.push("low_usefulness");
|
|
763
|
-
}
|
|
764
|
-
if (entity.type === "procedure") {
|
|
765
|
-
score += 0.1;
|
|
766
|
-
reasons.push("procedure_boost");
|
|
767
|
-
}
|
|
768
|
-
if (graphRelations && graphRelations.length > 0) {
|
|
769
|
-
const entityRelations = graphRelations.filter((r) => r.source_id === entity.id || r.target_id === entity.id);
|
|
770
|
-
if (entityRelations.length > 0) {
|
|
771
|
-
let bestBonus = 0;
|
|
772
|
-
let bestRelType = "";
|
|
773
|
-
for (const rel of entityRelations) {
|
|
774
|
-
const bonus = RELATION_BONUSES[rel.relation_type] ?? 0.1;
|
|
775
|
-
if (bonus > bestBonus) {
|
|
776
|
-
bestBonus = bonus;
|
|
777
|
-
bestRelType = rel.relation_type;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
score += bestBonus;
|
|
781
|
-
reasons.push(`graph_walk(${bestRelType})`);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
score = Math.max(0, Math.min(score, 1));
|
|
785
|
-
const tierWeight = TIER_WEIGHTS[entity.memory_tier];
|
|
786
|
-
score *= tierWeight;
|
|
787
|
-
return { score, reasons };
|
|
788
|
-
}
|
|
789
|
-
async function assembleContext(options) {
|
|
790
|
-
const {
|
|
791
|
-
workspaceId,
|
|
792
|
-
projectId,
|
|
793
|
-
taskContext,
|
|
794
|
-
cardLabels = [],
|
|
795
|
-
tokenBudget = DEFAULT_TOKEN_BUDGET,
|
|
796
|
-
client: client2,
|
|
797
|
-
graphWalkEnabled = true,
|
|
798
|
-
queryExpansionEnabled = true,
|
|
799
|
-
enableLlmReranking = false,
|
|
800
|
-
rerankFn
|
|
801
|
-
} = options;
|
|
802
|
-
const assemblyId = generateAssemblyId();
|
|
803
|
-
const manifest = {
|
|
804
|
-
assemblyId,
|
|
805
|
-
timestamp: new Date().toISOString(),
|
|
806
|
-
included: [],
|
|
807
|
-
excluded: [],
|
|
808
|
-
budgetUsed: 0,
|
|
809
|
-
budgetTotal: tokenBudget,
|
|
810
|
-
tierBreakdown: {
|
|
811
|
-
draft: { count: 0, tokens: 0 },
|
|
812
|
-
episode: { count: 0, tokens: 0 },
|
|
813
|
-
reference: { count: 0, tokens: 0 }
|
|
814
|
-
}
|
|
815
|
-
};
|
|
816
|
-
const candidates = [];
|
|
817
|
-
const queries = queryExpansionEnabled ? expandQuery(taskContext) : [taskContext];
|
|
818
|
-
const searchResults = await Promise.allSettled(queries.map((query) => client2.searchMemoryEntities(workspaceId, query, {
|
|
819
|
-
project_id: projectId,
|
|
820
|
-
limit: 30
|
|
821
|
-
})));
|
|
822
|
-
const candidateIds = new Set;
|
|
823
|
-
for (const result of searchResults) {
|
|
824
|
-
if (result.status !== "fulfilled")
|
|
825
|
-
continue;
|
|
826
|
-
if (result.value.entities?.length > 0) {
|
|
827
|
-
for (const raw of result.value.entities) {
|
|
828
|
-
const entity = mapToContextEntity(raw);
|
|
829
|
-
if (!candidateIds.has(entity.id)) {
|
|
830
|
-
candidateIds.add(entity.id);
|
|
831
|
-
candidates.push(entity);
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
if (candidates.length < 10 && projectId) {
|
|
837
|
-
try {
|
|
838
|
-
const listResult = await client2.listMemoryEntities({
|
|
839
|
-
workspace_id: workspaceId,
|
|
840
|
-
project_id: projectId,
|
|
841
|
-
limit: 30
|
|
842
|
-
});
|
|
843
|
-
if (listResult.entities?.length > 0) {
|
|
844
|
-
for (const raw of listResult.entities) {
|
|
845
|
-
const entity = mapToContextEntity(raw);
|
|
846
|
-
if (!candidateIds.has(entity.id)) {
|
|
847
|
-
candidateIds.add(entity.id);
|
|
848
|
-
candidates.push(entity);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
} catch {}
|
|
853
|
-
}
|
|
854
|
-
if (candidates.length < 20) {
|
|
855
|
-
try {
|
|
856
|
-
const wsResult = await client2.listMemoryEntities({
|
|
857
|
-
workspace_id: workspaceId,
|
|
858
|
-
scope: "workspace",
|
|
859
|
-
limit: 20
|
|
860
|
-
});
|
|
861
|
-
if (wsResult.entities?.length > 0) {
|
|
862
|
-
for (const raw of wsResult.entities) {
|
|
863
|
-
const entity = mapToContextEntity(raw);
|
|
864
|
-
if (!candidateIds.has(entity.id)) {
|
|
865
|
-
candidateIds.add(entity.id);
|
|
866
|
-
candidates.push(entity);
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
} catch {}
|
|
871
|
-
}
|
|
872
|
-
let graphRelations = [];
|
|
873
|
-
if (graphWalkEnabled && candidates.length > 0) {
|
|
874
|
-
try {
|
|
875
|
-
const seedCandidates = [...candidates].sort((a, b) => (b.rrf_score ?? 0) - (a.rrf_score ?? 0)).slice(0, GRAPH_WALK_SEED_COUNT);
|
|
876
|
-
const seedIds = seedCandidates.map((c) => c.id);
|
|
877
|
-
const walkResult = await discoverRelatedContext(client2, seedIds, GRAPH_WALK_MAX_DEPTH, GRAPH_WALK_MAX_ENTITIES, GRAPH_WALK_MIN_CONFIDENCE);
|
|
878
|
-
graphRelations = walkResult.relations;
|
|
879
|
-
const newEntityIds = walkResult.entities.filter((e) => !candidateIds.has(e.id)).map((e) => e.id);
|
|
880
|
-
if (newEntityIds.length > 0) {
|
|
881
|
-
const fetchResults = await Promise.allSettled(newEntityIds.map((id) => client2.getMemoryEntity(id)));
|
|
882
|
-
for (const result of fetchResults) {
|
|
883
|
-
if (result.status !== "fulfilled" || !result.value.entity)
|
|
884
|
-
continue;
|
|
885
|
-
const mapped = mapToContextEntity(result.value.entity);
|
|
886
|
-
candidateIds.add(mapped.id);
|
|
887
|
-
candidates.push(mapped);
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
} catch {}
|
|
891
|
-
}
|
|
892
|
-
if (candidates.length === 0) {
|
|
893
|
-
return {
|
|
894
|
-
context: "",
|
|
895
|
-
manifest,
|
|
896
|
-
memories: []
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
const qualityCandidates = candidates.filter((entity) => {
|
|
900
|
-
if (passesQualityGate(entity))
|
|
901
|
-
return true;
|
|
902
|
-
manifest.excluded.push({
|
|
903
|
-
entityId: entity.id,
|
|
904
|
-
title: entity.title,
|
|
905
|
-
type: entity.type,
|
|
906
|
-
tier: entity.memory_tier,
|
|
907
|
-
relevanceScore: 0,
|
|
908
|
-
reason: "failed_quality_gate"
|
|
909
|
-
});
|
|
910
|
-
return false;
|
|
911
|
-
});
|
|
912
|
-
if (qualityCandidates.length === 0) {
|
|
913
|
-
return {
|
|
914
|
-
context: "",
|
|
915
|
-
manifest,
|
|
916
|
-
memories: []
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
const scored = qualityCandidates.map((entity) => {
|
|
920
|
-
const { score, reasons } = computeRelevanceScore(entity, taskContext, cardLabels, graphRelations.length > 0 ? graphRelations : undefined);
|
|
921
|
-
return { entity, score, reasons };
|
|
922
|
-
});
|
|
923
|
-
scored.sort((a, b) => b.score - a.score);
|
|
924
|
-
if (enableLlmReranking && rerankFn && scored.length >= RERANK_MIN_CANDIDATES) {
|
|
925
|
-
const topN = scored.slice(0, RERANK_TOP_N);
|
|
926
|
-
const scoreRange = topN[0].score - topN[topN.length - 1].score;
|
|
927
|
-
if (scoreRange <= RERANK_CLUSTER_THRESHOLD) {
|
|
928
|
-
try {
|
|
929
|
-
const rerankCandidates = topN.map((s) => ({
|
|
930
|
-
id: s.entity.id,
|
|
931
|
-
title: s.entity.title,
|
|
932
|
-
snippet: s.entity.content.slice(0, 200)
|
|
933
|
-
}));
|
|
934
|
-
const rerankedIds = await rerankFn(taskContext, rerankCandidates);
|
|
935
|
-
const idOrder = new Map(rerankedIds.map((id, i) => [id, i]));
|
|
936
|
-
topN.sort((a, b) => {
|
|
937
|
-
const aIdx = idOrder.get(a.entity.id) ?? 999;
|
|
938
|
-
const bIdx = idOrder.get(b.entity.id) ?? 999;
|
|
939
|
-
return aIdx - bIdx;
|
|
940
|
-
});
|
|
941
|
-
scored.splice(0, topN.length, ...topN);
|
|
942
|
-
} catch {}
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
const procedureBudget = Math.floor(tokenBudget * PROCEDURE_BUDGET_FRACTION);
|
|
946
|
-
const remainingBudget = tokenBudget - procedureBudget;
|
|
947
|
-
const tierBudgets = {
|
|
948
|
-
reference: Math.floor(remainingBudget * TIER_BUDGET_ALLOCATION.reference),
|
|
949
|
-
episode: Math.floor(remainingBudget * TIER_BUDGET_ALLOCATION.episode),
|
|
950
|
-
draft: Math.floor(remainingBudget * TIER_BUDGET_ALLOCATION.draft)
|
|
951
|
-
};
|
|
952
|
-
const tierUsed = {
|
|
953
|
-
reference: 0,
|
|
954
|
-
episode: 0,
|
|
955
|
-
draft: 0
|
|
956
|
-
};
|
|
957
|
-
let procedureUsed = 0;
|
|
958
|
-
const included = [];
|
|
959
|
-
let totalUsed = 0;
|
|
960
|
-
let referenceCount = 0;
|
|
961
|
-
for (const item of scored) {
|
|
962
|
-
if (item.entity.memory_tier === "reference" && item.entity.type !== "procedure" && referenceCount < MIN_REFERENCE_SLOTS) {
|
|
963
|
-
const { text, truncated } = truncateContent(item.entity.content, MAX_TOKENS_PER_ENTITY);
|
|
964
|
-
const tokens = estimateTokens(`### ${item.entity.title}
|
|
965
|
-
${text}`);
|
|
966
|
-
if (totalUsed + tokens <= tokenBudget) {
|
|
967
|
-
included.push({ ...item, tokens, truncated });
|
|
968
|
-
item.entity.content = text;
|
|
969
|
-
totalUsed += tokens;
|
|
970
|
-
tierUsed.reference += tokens;
|
|
971
|
-
referenceCount++;
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
const includedIds = new Set(included.map((i) => i.entity.id));
|
|
976
|
-
const procedureCandidates = scored.filter((item) => item.entity.type === "procedure" && !includedIds.has(item.entity.id));
|
|
977
|
-
for (const item of procedureCandidates) {
|
|
978
|
-
if (item.score < MIN_RELEVANCE_THRESHOLD) {
|
|
979
|
-
manifest.excluded.push({
|
|
980
|
-
entityId: item.entity.id,
|
|
981
|
-
title: item.entity.title,
|
|
982
|
-
type: item.entity.type,
|
|
983
|
-
tier: item.entity.memory_tier,
|
|
984
|
-
relevanceScore: item.score,
|
|
985
|
-
reason: "below_relevance_threshold"
|
|
986
|
-
});
|
|
987
|
-
continue;
|
|
988
|
-
}
|
|
989
|
-
const { text, truncated } = truncateContent(item.entity.content, MAX_TOKENS_PER_ENTITY);
|
|
990
|
-
const tokens = estimateTokens(`### ${item.entity.title}
|
|
991
|
-
${text}`);
|
|
992
|
-
if (procedureUsed + tokens > procedureBudget) {
|
|
993
|
-
const totalRemaining = tokenBudget - totalUsed;
|
|
994
|
-
if (tokens > totalRemaining) {
|
|
995
|
-
manifest.excluded.push({
|
|
996
|
-
entityId: item.entity.id,
|
|
997
|
-
title: item.entity.title,
|
|
998
|
-
type: item.entity.type,
|
|
999
|
-
tier: item.entity.memory_tier,
|
|
1000
|
-
relevanceScore: item.score,
|
|
1001
|
-
reason: "procedure_budget_exceeded"
|
|
1002
|
-
});
|
|
1003
|
-
continue;
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
if (totalUsed + tokens > tokenBudget) {
|
|
1007
|
-
manifest.excluded.push({
|
|
1008
|
-
entityId: item.entity.id,
|
|
1009
|
-
title: item.entity.title,
|
|
1010
|
-
type: item.entity.type,
|
|
1011
|
-
tier: item.entity.memory_tier,
|
|
1012
|
-
relevanceScore: item.score,
|
|
1013
|
-
reason: "total_budget_exceeded"
|
|
1014
|
-
});
|
|
1015
|
-
continue;
|
|
1016
|
-
}
|
|
1017
|
-
included.push({ ...item, tokens, truncated });
|
|
1018
|
-
item.entity.content = text;
|
|
1019
|
-
totalUsed += tokens;
|
|
1020
|
-
procedureUsed += tokens;
|
|
1021
|
-
includedIds.add(item.entity.id);
|
|
1022
|
-
}
|
|
1023
|
-
for (const item of scored) {
|
|
1024
|
-
if (includedIds.has(item.entity.id))
|
|
1025
|
-
continue;
|
|
1026
|
-
if (item.entity.type === "procedure")
|
|
1027
|
-
continue;
|
|
1028
|
-
if (item.score < MIN_RELEVANCE_THRESHOLD) {
|
|
1029
|
-
manifest.excluded.push({
|
|
1030
|
-
entityId: item.entity.id,
|
|
1031
|
-
title: item.entity.title,
|
|
1032
|
-
type: item.entity.type,
|
|
1033
|
-
tier: item.entity.memory_tier,
|
|
1034
|
-
relevanceScore: item.score,
|
|
1035
|
-
reason: "below_relevance_threshold"
|
|
1036
|
-
});
|
|
1037
|
-
continue;
|
|
1038
|
-
}
|
|
1039
|
-
const tier = item.entity.memory_tier;
|
|
1040
|
-
const { text, truncated } = truncateContent(item.entity.content, MAX_TOKENS_PER_ENTITY);
|
|
1041
|
-
const tokens = estimateTokens(`### ${item.entity.title}
|
|
1042
|
-
${text}`);
|
|
1043
|
-
if (tierUsed[tier] + tokens > tierBudgets[tier]) {
|
|
1044
|
-
const totalRemaining = tokenBudget - totalUsed;
|
|
1045
|
-
if (tokens > totalRemaining) {
|
|
1046
|
-
manifest.excluded.push({
|
|
1047
|
-
entityId: item.entity.id,
|
|
1048
|
-
title: item.entity.title,
|
|
1049
|
-
type: item.entity.type,
|
|
1050
|
-
tier,
|
|
1051
|
-
relevanceScore: item.score,
|
|
1052
|
-
reason: "budget_exceeded"
|
|
1053
|
-
});
|
|
1054
|
-
continue;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
if (totalUsed + tokens > tokenBudget) {
|
|
1058
|
-
manifest.excluded.push({
|
|
1059
|
-
entityId: item.entity.id,
|
|
1060
|
-
title: item.entity.title,
|
|
1061
|
-
type: item.entity.type,
|
|
1062
|
-
tier,
|
|
1063
|
-
relevanceScore: item.score,
|
|
1064
|
-
reason: "total_budget_exceeded"
|
|
1065
|
-
});
|
|
1066
|
-
continue;
|
|
1067
|
-
}
|
|
1068
|
-
included.push({ ...item, tokens, truncated });
|
|
1069
|
-
item.entity.content = text;
|
|
1070
|
-
totalUsed += tokens;
|
|
1071
|
-
tierUsed[tier] += tokens;
|
|
1072
|
-
includedIds.add(item.entity.id);
|
|
1073
|
-
}
|
|
1074
|
-
manifest.budgetUsed = totalUsed;
|
|
1075
|
-
const procedureItems = included.filter((i) => i.entity.type === "procedure");
|
|
1076
|
-
manifest.tierBreakdown = {
|
|
1077
|
-
reference: {
|
|
1078
|
-
count: included.filter((i) => i.entity.memory_tier === "reference" && i.entity.type !== "procedure").length,
|
|
1079
|
-
tokens: tierUsed.reference
|
|
1080
|
-
},
|
|
1081
|
-
episode: {
|
|
1082
|
-
count: included.filter((i) => i.entity.memory_tier === "episode" && i.entity.type !== "procedure").length,
|
|
1083
|
-
tokens: tierUsed.episode
|
|
1084
|
-
},
|
|
1085
|
-
draft: {
|
|
1086
|
-
count: included.filter((i) => i.entity.memory_tier === "draft" && i.entity.type !== "procedure").length,
|
|
1087
|
-
tokens: tierUsed.draft
|
|
1088
|
-
}
|
|
1089
|
-
};
|
|
1090
|
-
manifest.procedureBreakdown = {
|
|
1091
|
-
count: procedureItems.length,
|
|
1092
|
-
tokens: procedureUsed,
|
|
1093
|
-
budget: procedureBudget
|
|
1094
|
-
};
|
|
1095
|
-
for (const item of included) {
|
|
1096
|
-
manifest.included.push({
|
|
1097
|
-
entityId: item.entity.id,
|
|
1098
|
-
title: item.entity.title,
|
|
1099
|
-
type: item.entity.type,
|
|
1100
|
-
tier: item.entity.memory_tier,
|
|
1101
|
-
relevanceScore: item.score,
|
|
1102
|
-
reasons: item.reasons,
|
|
1103
|
-
tokenCount: item.tokens,
|
|
1104
|
-
truncated: item.truncated
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1107
|
-
const contextSections = [];
|
|
1108
|
-
const nonProcedureItems = included.filter((i) => i.entity.type !== "procedure");
|
|
1109
|
-
if (included.length > 0) {
|
|
1110
|
-
if (procedureItems.length > 0) {
|
|
1111
|
-
contextSections.push(`## Procedures (${procedureItems.length} loaded, ${procedureUsed}/${procedureBudget} tokens)`);
|
|
1112
|
-
for (const item of procedureItems) {
|
|
1113
|
-
const tags = item.entity.tags.length > 0 ? ` [${item.entity.tags.join(", ")}]` : "";
|
|
1114
|
-
const tierLabel = item.entity.memory_tier !== "reference" ? ` (${item.entity.memory_tier})` : "";
|
|
1115
|
-
contextSections.push(`
|
|
1116
|
-
### ${item.entity.title} (confidence: ${item.entity.confidence})${tierLabel}${tags}`);
|
|
1117
|
-
contextSections.push(item.entity.content);
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
if (nonProcedureItems.length > 0) {
|
|
1121
|
-
contextSections.push(`
|
|
1122
|
-
## Relevant Memories (${nonProcedureItems.length} loaded, ${manifest.excluded.length} excluded)`);
|
|
1123
|
-
contextSections.push(`*Assembly: ${assemblyId} | Budget: ${totalUsed}/${tokenBudget} tokens*`);
|
|
1124
|
-
for (const item of nonProcedureItems) {
|
|
1125
|
-
const tags = item.entity.tags.length > 0 ? ` [${item.entity.tags.join(", ")}]` : "";
|
|
1126
|
-
const tierLabel = item.entity.memory_tier !== "reference" ? ` (${item.entity.memory_tier})` : "";
|
|
1127
|
-
contextSections.push(`
|
|
1128
|
-
### ${item.entity.title} (${item.entity.type}, confidence: ${item.entity.confidence})${tierLabel}${tags}`);
|
|
1129
|
-
contextSections.push(item.entity.content);
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
incrementAccessCounts(client2, included.map((i) => i.entity.id)).catch(() => {});
|
|
1134
|
-
promoteEligibleEntities(client2, included.map((i) => i.entity)).catch(() => {});
|
|
1135
|
-
return {
|
|
1136
|
-
context: contextSections.join(`
|
|
1137
|
-
`),
|
|
1138
|
-
manifest,
|
|
1139
|
-
memories: included.map((i) => i.entity)
|
|
1140
|
-
};
|
|
1141
|
-
}
|
|
1142
|
-
function mapToContextEntity(raw) {
|
|
1143
|
-
const e = raw;
|
|
1144
|
-
return {
|
|
1145
|
-
id: e.id,
|
|
1146
|
-
type: e.type,
|
|
1147
|
-
title: e.title,
|
|
1148
|
-
content: e.content,
|
|
1149
|
-
confidence: e.confidence ?? 1,
|
|
1150
|
-
tags: e.tags || [],
|
|
1151
|
-
memory_tier: e.memory_tier || "reference",
|
|
1152
|
-
access_count: e.access_count || 0,
|
|
1153
|
-
last_accessed_at: e.last_accessed_at || null,
|
|
1154
|
-
created_at: e.created_at || "",
|
|
1155
|
-
updated_at: e.updated_at || "",
|
|
1156
|
-
metadata: e.metadata ?? undefined,
|
|
1157
|
-
rrf_score: e.rrf_score ?? undefined,
|
|
1158
|
-
fts_rank: e.fts_rank ?? undefined,
|
|
1159
|
-
semantic_rank: e.semantic_rank ?? undefined
|
|
1160
|
-
};
|
|
1161
|
-
}
|
|
1162
|
-
async function incrementAccessCounts(client2, entityIds) {
|
|
1163
|
-
if (entityIds.length === 0)
|
|
1164
|
-
return;
|
|
1165
|
-
try {
|
|
1166
|
-
await client2.batchTouchMemoryEntities(entityIds);
|
|
1167
|
-
} catch {
|
|
1168
|
-
await Promise.allSettled(entityIds.map((id) => client2.touchMemoryEntity(id)));
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
async function promoteEligibleEntities(client2, entities) {
|
|
1172
|
-
for (const entity of entities) {
|
|
1173
|
-
if (entity.memory_tier === "reference")
|
|
1174
|
-
continue;
|
|
1175
|
-
if (!entity.created_at)
|
|
1176
|
-
continue;
|
|
1177
|
-
const promotion = checkPromotion(entity.memory_tier, entity.access_count + 1, entity.confidence, entity.created_at);
|
|
1178
|
-
if (promotion.eligible && promotion.targetTier) {
|
|
1179
|
-
try {
|
|
1180
|
-
await client2.updateMemoryEntity(entity.id, {
|
|
1181
|
-
memory_tier: promotion.targetTier,
|
|
1182
|
-
metadata: {
|
|
1183
|
-
...entity.metadata || {},
|
|
1184
|
-
promoted_at: new Date().toISOString(),
|
|
1185
|
-
promotion_reason: promotion.reason,
|
|
1186
|
-
promoted_from: entity.memory_tier
|
|
1187
|
-
}
|
|
1188
|
-
});
|
|
1189
|
-
} catch {}
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
function cacheManifest(manifest) {
|
|
1194
|
-
if (manifestCache.size >= MAX_CACHE_SIZE) {
|
|
1195
|
-
const firstKey = manifestCache.keys().next().value;
|
|
1196
|
-
if (firstKey)
|
|
1197
|
-
manifestCache.delete(firstKey);
|
|
1198
|
-
}
|
|
1199
|
-
manifestCache.set(manifest.assemblyId, manifest);
|
|
1200
|
-
}
|
|
1201
|
-
function getCachedManifest(assemblyId) {
|
|
1202
|
-
return manifestCache.get(assemblyId);
|
|
1203
|
-
}
|
|
1204
|
-
function trackSessionAssembly(cardId, assemblyId) {
|
|
1205
|
-
if (sessionAssemblyMap.size >= MAX_SESSION_MAP_SIZE) {
|
|
1206
|
-
const firstKey = sessionAssemblyMap.keys().next().value;
|
|
1207
|
-
if (firstKey)
|
|
1208
|
-
sessionAssemblyMap.delete(firstKey);
|
|
1209
|
-
}
|
|
1210
|
-
sessionAssemblyMap.set(cardId, assemblyId);
|
|
1211
|
-
}
|
|
1212
|
-
function getSessionAssemblyId(cardId) {
|
|
1213
|
-
return sessionAssemblyMap.get(cardId);
|
|
1214
|
-
}
|
|
1215
|
-
async function recordContextFeedback(client2, cardId, sessionStatus, progressPercent, hadBlockers) {
|
|
1216
|
-
const assemblyId = sessionAssemblyMap.get(cardId);
|
|
1217
|
-
if (!assemblyId)
|
|
1218
|
-
return { adjusted: 0 };
|
|
1219
|
-
const manifest = manifestCache.get(assemblyId);
|
|
1220
|
-
if (!manifest || manifest.included.length === 0)
|
|
1221
|
-
return { adjusted: 0 };
|
|
1222
|
-
let adjusted = 0;
|
|
1223
|
-
const isSuccess = sessionStatus === "completed" && (progressPercent ?? 0) >= 100;
|
|
1224
|
-
for (const entry of manifest.included) {
|
|
1225
|
-
try {
|
|
1226
|
-
if (isSuccess) {
|
|
1227
|
-
const { entity } = await client2.getMemoryEntity(entry.entityId);
|
|
1228
|
-
const e = entity;
|
|
1229
|
-
const currentUsefulness = e.metadata?.usefulness_score ?? 0;
|
|
1230
|
-
const newConfidence = Math.min((e.confidence ?? 0.5) + 0.05, 1);
|
|
1231
|
-
await client2.updateMemoryEntity(entry.entityId, {
|
|
1232
|
-
confidence: newConfidence,
|
|
1233
|
-
metadata: {
|
|
1234
|
-
usefulness_score: currentUsefulness + 1,
|
|
1235
|
-
last_feedback_at: new Date().toISOString()
|
|
1236
|
-
}
|
|
1237
|
-
});
|
|
1238
|
-
adjusted++;
|
|
1239
|
-
} else if (hadBlockers) {
|
|
1240
|
-
const { entity } = await client2.getMemoryEntity(entry.entityId);
|
|
1241
|
-
const e = entity;
|
|
1242
|
-
const newConfidence = Math.max((e.confidence ?? 0.5) - 0.02, 0.1);
|
|
1243
|
-
await client2.updateMemoryEntity(entry.entityId, {
|
|
1244
|
-
confidence: newConfidence,
|
|
1245
|
-
metadata: {
|
|
1246
|
-
last_feedback_at: new Date().toISOString()
|
|
1247
|
-
}
|
|
1248
|
-
});
|
|
1249
|
-
adjusted++;
|
|
1250
|
-
}
|
|
1251
|
-
} catch {}
|
|
1252
|
-
}
|
|
1253
|
-
sessionAssemblyMap.delete(cardId);
|
|
1254
|
-
return { adjusted };
|
|
1255
|
-
}
|
|
1256
|
-
var DEFAULT_TOKEN_BUDGET = 4000, MAX_TOKENS_PER_ENTITY = 500, MIN_RELEVANCE_THRESHOLD = 0.15, TIER_WEIGHTS, PROCEDURE_BUDGET_FRACTION = 0.15, TIER_BUDGET_ALLOCATION, MIN_REFERENCE_SLOTS = 1, GRAPH_WALK_MAX_DEPTH = 1, GRAPH_WALK_MAX_ENTITIES = 10, GRAPH_WALK_MIN_CONFIDENCE = 0.5, GRAPH_WALK_SEED_COUNT = 5, MAX_QUERY_VARIATIONS = 4, RERANK_CLUSTER_THRESHOLD = 0.05, RERANK_TOP_N = 10, RERANK_MIN_CANDIDATES = 5, RELATION_BONUSES, QUERY_SYNONYMS, manifestCache, MAX_CACHE_SIZE = 50, sessionAssemblyMap, MAX_SESSION_MAP_SIZE = 100;
|
|
1257
|
-
var init_context_assembly = __esm(() => {
|
|
1258
|
-
init_dist();
|
|
1259
|
-
TIER_WEIGHTS = {
|
|
1260
|
-
reference: 1,
|
|
1261
|
-
episode: 0.7,
|
|
1262
|
-
draft: 0.4
|
|
1263
|
-
};
|
|
1264
|
-
TIER_BUDGET_ALLOCATION = {
|
|
1265
|
-
reference: 0.6,
|
|
1266
|
-
episode: 0.3,
|
|
1267
|
-
draft: 0.1
|
|
1268
|
-
};
|
|
1269
|
-
RELATION_BONUSES = {
|
|
1270
|
-
depends_on: 0.15,
|
|
1271
|
-
resolved_by: 0.2,
|
|
1272
|
-
relates_to: 0.1,
|
|
1273
|
-
implements: 0.15,
|
|
1274
|
-
blocks: 0.15,
|
|
1275
|
-
references: 0.1,
|
|
1276
|
-
extends: 0.1,
|
|
1277
|
-
caused_by: 0.15
|
|
1278
|
-
};
|
|
1279
|
-
QUERY_SYNONYMS = {
|
|
1280
|
-
auth: ["authentication", "authorization", "session"],
|
|
1281
|
-
authentication: ["auth", "session", "sign-in"],
|
|
1282
|
-
login: ["sign-in", "authentication", "session"],
|
|
1283
|
-
bug: ["error", "issue", "defect", "problem"],
|
|
1284
|
-
error: ["exception", "failure", "issue"],
|
|
1285
|
-
fix: ["resolve", "patch", "repair", "correct"],
|
|
1286
|
-
deploy: ["deployment", "release", "ship", "publish"],
|
|
1287
|
-
test: ["testing", "spec", "assertion", "verify"],
|
|
1288
|
-
config: ["configuration", "settings", "setup"],
|
|
1289
|
-
db: ["database", "storage", "persistence"],
|
|
1290
|
-
database: ["storage", "persistence", "data store"],
|
|
1291
|
-
api: ["endpoint", "route", "service"],
|
|
1292
|
-
ui: ["frontend", "component", "view"],
|
|
1293
|
-
perf: ["performance", "speed", "latency"],
|
|
1294
|
-
performance: ["speed", "latency", "optimization"]
|
|
1295
|
-
};
|
|
1296
|
-
manifestCache = new Map;
|
|
1297
|
-
sessionAssemblyMap = new Map;
|
|
1298
|
-
});
|
|
1299
|
-
init_context_assembly();
|
|
1300
|
-
|
|
1301
|
-
export {
|
|
1302
|
-
trackSessionAssembly,
|
|
1303
|
-
recordContextFeedback,
|
|
1304
|
-
mapToContextEntity,
|
|
1305
|
-
getSessionAssemblyId,
|
|
1306
|
-
getCachedManifest,
|
|
1307
|
-
expandQuery,
|
|
1308
|
-
computeRelevanceScore,
|
|
1309
|
-
cacheManifest,
|
|
1310
|
-
assembleContext
|
|
1311
|
-
};
|