context-vault 3.0.2 → 3.0.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/bin/cli.js +14 -0
- package/node_modules/@context-vault/core/package.json +1 -1
- package/node_modules/@context-vault/core/src/capture.ts +2 -2
- package/node_modules/@context-vault/core/src/index.ts +4 -2
- package/package.json +2 -2
- package/src/register-tools.js +2 -0
- package/src/tools/save-context.js +7 -4
package/bin/cli.js
CHANGED
|
@@ -3598,6 +3598,8 @@ async function runSave() {
|
|
|
3598
3598
|
const tier = getFlag("--tier");
|
|
3599
3599
|
const filePath = getFlag("--file");
|
|
3600
3600
|
const bodyFlag = getFlag("--body");
|
|
3601
|
+
const identityKey = getFlag("--identity-key");
|
|
3602
|
+
const metaRaw = getFlag("--meta");
|
|
3601
3603
|
|
|
3602
3604
|
if (!kind) {
|
|
3603
3605
|
console.error(red("Error: --kind is required"));
|
|
@@ -3608,6 +3610,16 @@ async function runSave() {
|
|
|
3608
3610
|
process.exit(1);
|
|
3609
3611
|
}
|
|
3610
3612
|
|
|
3613
|
+
let meta;
|
|
3614
|
+
if (metaRaw) {
|
|
3615
|
+
try {
|
|
3616
|
+
meta = JSON.parse(metaRaw);
|
|
3617
|
+
} catch {
|
|
3618
|
+
console.error(red("Error: --meta must be valid JSON"));
|
|
3619
|
+
process.exit(1);
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3611
3623
|
let body;
|
|
3612
3624
|
if (bodyFlag) {
|
|
3613
3625
|
body = bodyFlag;
|
|
@@ -3665,6 +3677,8 @@ async function runSave() {
|
|
|
3665
3677
|
tags: parsedTags,
|
|
3666
3678
|
source,
|
|
3667
3679
|
...(tier ? { tier } : {}),
|
|
3680
|
+
...(identityKey ? { identity_key: identityKey } : {}),
|
|
3681
|
+
...(meta !== undefined ? { meta } : {}),
|
|
3668
3682
|
});
|
|
3669
3683
|
console.log(`${green("✓")} Saved ${kind} — id: ${entry.id}`);
|
|
3670
3684
|
} catch (e) {
|
|
@@ -266,7 +266,7 @@ export function updateEntryFile(
|
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput): Promise<CaptureResult> {
|
|
269
|
+
export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput, precomputedEmbedding?: Float32Array | null): Promise<CaptureResult> {
|
|
270
270
|
let previousContent: string | null = null;
|
|
271
271
|
if (categoryFor(data.kind) === "entity" && data.identity_key) {
|
|
272
272
|
const identitySlug = slugify(data.identity_key);
|
|
@@ -279,7 +279,7 @@ export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput): Promise
|
|
|
279
279
|
|
|
280
280
|
const entry = writeEntry(ctx, data);
|
|
281
281
|
try {
|
|
282
|
-
await indexEntry(ctx, entry);
|
|
282
|
+
await indexEntry(ctx, entry, precomputedEmbedding);
|
|
283
283
|
if (entry.supersedes?.length && ctx.stmts.updateSupersededBy) {
|
|
284
284
|
for (const supersededId of entry.supersedes) {
|
|
285
285
|
if (typeof supersededId === "string" && supersededId.trim()) {
|
|
@@ -13,6 +13,7 @@ const EMBED_BATCH_SIZE = 32;
|
|
|
13
13
|
export async function indexEntry(
|
|
14
14
|
ctx: BaseCtx,
|
|
15
15
|
entry: IndexEntryInput & { supersedes?: string[] | null; related_to?: string[] | null },
|
|
16
|
+
precomputedEmbedding?: Float32Array | null,
|
|
16
17
|
): Promise<void> {
|
|
17
18
|
const {
|
|
18
19
|
id, kind, category, title, body, meta, tags, source,
|
|
@@ -92,8 +93,9 @@ export async function indexEntry(
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
if (cat !== "event") {
|
|
95
|
-
const
|
|
96
|
-
|
|
96
|
+
const embedding = precomputedEmbedding !== undefined
|
|
97
|
+
? precomputedEmbedding
|
|
98
|
+
: await ctx.embed([title, body].filter(Boolean).join(" "));
|
|
97
99
|
|
|
98
100
|
if (embedding) {
|
|
99
101
|
try { ctx.deleteVec(rowid); } catch { /* no-op */ }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-vault",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Persistent memory for AI agents — saves and searches knowledge across sessions",
|
|
6
6
|
"bin": {
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"@context-vault/core"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@context-vault/core": "^3.0.
|
|
60
|
+
"@context-vault/core": "^3.0.3",
|
|
61
61
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
62
62
|
"adm-zip": "^0.5.16",
|
|
63
63
|
"sqlite-vec": "^0.1.0"
|
package/src/register-tools.js
CHANGED
|
@@ -484,17 +484,18 @@ export async function handler(
|
|
|
484
484
|
// ── Similarity check (knowledge + event only) ────────────────────────────
|
|
485
485
|
const category = categoryFor(normalizedKind);
|
|
486
486
|
let similarEntries = [];
|
|
487
|
+
let queryEmbedding = null;
|
|
487
488
|
|
|
488
489
|
if (category === "knowledge" || category === "event") {
|
|
489
490
|
const threshold = similarity_threshold ?? DEFAULT_SIMILARITY_THRESHOLD;
|
|
490
491
|
const embeddingText = [title, body].filter(Boolean).join(" ");
|
|
491
|
-
|
|
492
|
+
queryEmbedding = await ctx.embed(embeddingText);
|
|
492
493
|
if (queryEmbedding) {
|
|
493
494
|
similarEntries = await findSimilar(
|
|
494
495
|
ctx,
|
|
495
496
|
queryEmbedding,
|
|
496
497
|
threshold,
|
|
497
|
-
|
|
498
|
+
|
|
498
499
|
{ hydrate: suggestMode },
|
|
499
500
|
);
|
|
500
501
|
}
|
|
@@ -540,6 +541,8 @@ export async function handler(
|
|
|
540
541
|
|
|
541
542
|
const effectiveTier = tier ?? defaultTierFor(normalizedKind);
|
|
542
543
|
|
|
544
|
+
const embeddingToReuse = category === "knowledge" ? queryEmbedding : null;
|
|
545
|
+
|
|
543
546
|
const entry = await captureAndIndex(ctx, {
|
|
544
547
|
kind: normalizedKind,
|
|
545
548
|
title,
|
|
@@ -553,9 +556,9 @@ export async function handler(
|
|
|
553
556
|
supersedes,
|
|
554
557
|
related_to,
|
|
555
558
|
source_files,
|
|
556
|
-
|
|
559
|
+
|
|
557
560
|
tier: effectiveTier,
|
|
558
|
-
});
|
|
561
|
+
}, embeddingToReuse);
|
|
559
562
|
|
|
560
563
|
if (ctx.config?.dataDir) {
|
|
561
564
|
maybeShowFeedbackPrompt(ctx.config.dataDir);
|