@aeriondyseti/vector-memory-mcp 2.2.3 → 2.2.6-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -13
- package/package.json +12 -12
- package/{src → server}/config/index.ts +10 -2
- package/{src/db → server/core}/connection.ts +10 -2
- package/{src/db → server/core}/conversation.repository.ts +1 -1
- package/{src/services → server/core}/conversation.service.ts +2 -2
- package/server/core/embeddings.service.ts +125 -0
- package/{src/db → server/core}/memory.repository.ts +5 -1
- package/{src/services → server/core}/memory.service.ts +20 -4
- package/server/core/migration.service.ts +882 -0
- package/server/core/migrations.ts +263 -0
- package/{src/services → server/core}/parsers/claude-code.parser.ts +1 -1
- package/{src/services → server/core}/parsers/types.ts +1 -1
- package/{src → server}/index.ts +16 -48
- package/{src → server/transports}/http/mcp-transport.ts +2 -2
- package/{src → server/transports}/http/server.ts +6 -4
- package/{src → server/transports}/mcp/handlers.ts +5 -5
- package/server/transports/mcp/resources.ts +20 -0
- package/{src → server/transports}/mcp/server.ts +14 -3
- package/server/utils/formatting.ts +143 -0
- package/scripts/lancedb-extract.ts +0 -181
- package/scripts/migrate-from-lancedb.ts +0 -56
- package/scripts/smoke-test.ts +0 -699
- package/scripts/test-runner.ts +0 -76
- package/scripts/warmup.ts +0 -72
- package/src/db/migrations.ts +0 -108
- package/src/migration.ts +0 -203
- package/src/services/embeddings.service.ts +0 -48
- /package/{src/types → server/core}/conversation.ts +0 -0
- /package/{src/types → server/core}/memory.ts +0 -0
- /package/{src/db → server/core}/sqlite-utils.ts +0 -0
- /package/{src → server/transports}/mcp/tools.ts +0 -0
package/README.md
CHANGED
|
@@ -20,14 +20,27 @@ A local-first MCP server that provides vector-based memory storage. Uses local e
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Installation
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
There are two ways to install Vector Memory, depending on how much integration you want.
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
### Option A: Claude Code Plugin (recommended)
|
|
28
|
+
|
|
29
|
+
Install as a plugin to get the full experience: MCP server, session lifecycle hooks, waypoint skills, and context monitoring — all managed automatically.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Add the marketplace
|
|
33
|
+
claude plugin marketplace add AerionDyseti/vector-memory-mcp
|
|
34
|
+
|
|
35
|
+
# Install the plugin
|
|
36
|
+
claude plugin install vector-memory@vector-memory-mcp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This clones the repo and runs the MCP server directly from source. Hooks handle session start/clear/compact events, and skills provide `/waypoint:set`, `/waypoint:get`, and memory usage guidance.
|
|
40
|
+
|
|
41
|
+
### Option B: MCP Server Only
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
Install just the MCP server via npm if you want memory storage without hooks or skills, or if you're using a non-Claude Code MCP client.
|
|
31
44
|
|
|
32
45
|
```bash
|
|
33
46
|
bun install -g @aeriondyseti/vector-memory-mcp
|
|
@@ -35,9 +48,7 @@ bun install -g @aeriondyseti/vector-memory-mcp
|
|
|
35
48
|
|
|
36
49
|
> First install downloads ML models (~90MB). This may take a minute.
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Add to your MCP client config (e.g., `~/.claude/settings.json`):
|
|
51
|
+
Then add to your MCP client config (e.g., `~/.claude/settings.json`):
|
|
41
52
|
|
|
42
53
|
```json
|
|
43
54
|
{
|
|
@@ -51,9 +62,16 @@ Add to your MCP client config (e.g., `~/.claude/settings.json`):
|
|
|
51
62
|
}
|
|
52
63
|
```
|
|
53
64
|
|
|
54
|
-
###
|
|
65
|
+
### Prerequisites
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
- [Bun](https://bun.sh/) 1.0+
|
|
68
|
+
- An MCP-compatible client (Claude Code, Claude Desktop, etc.)
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Tools
|
|
73
|
+
|
|
74
|
+
Restart your MCP client after installation. You now have access to:
|
|
57
75
|
|
|
58
76
|
| Tool | Description |
|
|
59
77
|
|------|-------------|
|
|
@@ -116,7 +134,9 @@ CLI flags:
|
|
|
116
134
|
|
|
117
135
|
## Release Channels
|
|
118
136
|
|
|
119
|
-
The
|
|
137
|
+
**Plugin users:** The plugin tracks the repo's default branch. To switch channels, reinstall from a specific branch or tag.
|
|
138
|
+
|
|
139
|
+
**npm users:** The stable release is what you get by default:
|
|
120
140
|
|
|
121
141
|
```bash
|
|
122
142
|
bun install -g @aeriondyseti/vector-memory-mcp
|
|
@@ -124,8 +144,8 @@ bun install -g @aeriondyseti/vector-memory-mcp
|
|
|
124
144
|
|
|
125
145
|
Pre-release channels are available for testing upcoming changes. **These are unstable and may break without notice — use at your own risk.**
|
|
126
146
|
|
|
127
|
-
| Channel |
|
|
128
|
-
|
|
147
|
+
| Channel | npm | Description |
|
|
148
|
+
|---------|-----|-------------|
|
|
129
149
|
| `@latest` | *(default)* | Stable releases |
|
|
130
150
|
| `@rc` | `@aeriondyseti/vector-memory-mcp@rc` | Release candidates — final testing before stable |
|
|
131
151
|
| `@dev` | `@aeriondyseti/vector-memory-mcp@dev` | Development builds — latest features, least stable |
|
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeriondyseti/vector-memory-mcp",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.6-dev.1",
|
|
4
4
|
"description": "A zero-configuration RAG memory server for MCP clients",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "
|
|
6
|
+
"main": "server/index.ts",
|
|
7
7
|
"bin": {
|
|
8
|
-
"vector-memory-mcp": "
|
|
8
|
+
"vector-memory-mcp": "server/index.ts"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"
|
|
12
|
-
"scripts",
|
|
11
|
+
"server",
|
|
13
12
|
"README.md",
|
|
14
13
|
"LICENSE"
|
|
15
14
|
],
|
|
@@ -23,8 +22,8 @@
|
|
|
23
22
|
},
|
|
24
23
|
"homepage": "https://github.com/aeriondyseti/vector-memory-mcp#readme",
|
|
25
24
|
"scripts": {
|
|
26
|
-
"start": "bun run
|
|
27
|
-
"dev": "bun --watch run
|
|
25
|
+
"start": "bun run server/index.ts",
|
|
26
|
+
"dev": "bun --watch run server/index.ts",
|
|
28
27
|
"typecheck": "bunx tsc --noEmit",
|
|
29
28
|
"test": "bun run scripts/test-runner.ts",
|
|
30
29
|
"test:raw": "bun test --preload ./tests/preload.ts",
|
|
@@ -35,7 +34,8 @@
|
|
|
35
34
|
"smoke": "bun run scripts/smoke-test.ts",
|
|
36
35
|
"warmup": "bun run scripts/warmup.ts",
|
|
37
36
|
"postinstall": "bun run scripts/warmup.ts",
|
|
38
|
-
"prepublishOnly": "bunx tsc --noEmit"
|
|
37
|
+
"prepublishOnly": "bunx tsc --noEmit",
|
|
38
|
+
"postversion": "bun scripts/sync-version.ts"
|
|
39
39
|
},
|
|
40
40
|
"keywords": [
|
|
41
41
|
"mcp",
|
|
@@ -46,18 +46,18 @@
|
|
|
46
46
|
],
|
|
47
47
|
"license": "MIT",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@huggingface/
|
|
49
|
+
"@huggingface/tokenizers": "^0.1.3",
|
|
50
50
|
"@lancedb/lancedb": "^0.26.2",
|
|
51
51
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
52
52
|
"arg": "^5.0.2",
|
|
53
|
-
"hono": "^4.11.3"
|
|
53
|
+
"hono": "^4.11.3",
|
|
54
|
+
"onnxruntime-node": "^1.21.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/bun": "latest",
|
|
57
58
|
"typescript": "^5.0.0"
|
|
58
59
|
},
|
|
59
60
|
"trustedDependencies": [
|
|
60
|
-
"protobufjs"
|
|
61
|
-
"sharp"
|
|
61
|
+
"protobufjs"
|
|
62
62
|
]
|
|
63
63
|
}
|
|
@@ -28,6 +28,7 @@ export interface Config {
|
|
|
28
28
|
httpPort: number;
|
|
29
29
|
httpHost: string;
|
|
30
30
|
enableHttp: boolean;
|
|
31
|
+
pluginMode: boolean;
|
|
31
32
|
transportMode: TransportMode;
|
|
32
33
|
conversationHistory: ConversationHistoryConfig;
|
|
33
34
|
}
|
|
@@ -36,6 +37,7 @@ export interface ConfigOverrides {
|
|
|
36
37
|
dbPath?: string;
|
|
37
38
|
httpPort?: number;
|
|
38
39
|
enableHttp?: boolean;
|
|
40
|
+
pluginMode?: boolean;
|
|
39
41
|
transportMode?: TransportMode;
|
|
40
42
|
enableHistory?: boolean;
|
|
41
43
|
historyPath?: string;
|
|
@@ -55,8 +57,11 @@ function resolvePath(path: string): string {
|
|
|
55
57
|
|
|
56
58
|
export function loadConfig(overrides: ConfigOverrides = {}): Config {
|
|
57
59
|
const transportMode = overrides.transportMode ?? "stdio";
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
const pluginMode = overrides.pluginMode ?? false;
|
|
61
|
+
// HTTP enabled only in plugin mode (hooks need it). --no-http overrides.
|
|
62
|
+
// Force HTTP on if transport mode requires it, regardless of plugin mode.
|
|
63
|
+
const enableHttp = overrides.enableHttp
|
|
64
|
+
?? (transportMode === "http" || transportMode === "both" || pluginMode);
|
|
60
65
|
|
|
61
66
|
return {
|
|
62
67
|
dbPath: resolvePath(
|
|
@@ -74,6 +79,7 @@ export function loadConfig(overrides: ConfigOverrides = {}): Config {
|
|
|
74
79
|
?? DEFAULT_HTTP_PORT,
|
|
75
80
|
httpHost: DEFAULT_HTTP_HOST,
|
|
76
81
|
enableHttp,
|
|
82
|
+
pluginMode,
|
|
77
83
|
transportMode,
|
|
78
84
|
conversationHistory: {
|
|
79
85
|
enabled: overrides.enableHistory ?? false,
|
|
@@ -95,6 +101,7 @@ export function parseCliArgs(argv: string[]): ConfigOverrides {
|
|
|
95
101
|
"--db-file": String,
|
|
96
102
|
"--port": Number,
|
|
97
103
|
"--no-http": Boolean,
|
|
104
|
+
"--plugin": Boolean,
|
|
98
105
|
"--enable-history": Boolean,
|
|
99
106
|
"--history-path": String,
|
|
100
107
|
"--history-weight": Number,
|
|
@@ -110,6 +117,7 @@ export function parseCliArgs(argv: string[]): ConfigOverrides {
|
|
|
110
117
|
dbPath: args["--db-file"],
|
|
111
118
|
httpPort: args["--port"],
|
|
112
119
|
enableHttp: args["--no-http"] ? false : undefined,
|
|
120
|
+
pluginMode: args["--plugin"] ?? undefined,
|
|
113
121
|
enableHistory: args["--enable-history"] ?? undefined,
|
|
114
122
|
historyPath: args["--history-path"],
|
|
115
123
|
historyWeight: args["--history-weight"],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
|
-
import { mkdirSync } from "fs";
|
|
2
|
+
import { existsSync, mkdirSync } from "fs";
|
|
3
3
|
import { dirname } from "path";
|
|
4
|
-
import { runMigrations } from "./migrations.js";
|
|
4
|
+
import { removeVec0Tables, runMigrations } from "./migrations.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Open (or create) a SQLite database at the given path
|
|
@@ -9,6 +9,14 @@ import { runMigrations } from "./migrations.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export function connectToDatabase(dbPath: string): Database {
|
|
11
11
|
mkdirSync(dirname(dbPath), { recursive: true });
|
|
12
|
+
|
|
13
|
+
// Remove orphaned vec0 virtual table entries before bun:sqlite opens the
|
|
14
|
+
// database. bun:sqlite cannot modify sqlite_master, so this uses the
|
|
15
|
+
// sqlite3 CLI while no other connection holds a lock.
|
|
16
|
+
if (existsSync(dbPath)) {
|
|
17
|
+
removeVec0Tables(dbPath);
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
const db = new Database(dbPath);
|
|
13
21
|
|
|
14
22
|
// WAL mode for concurrent read performance
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "crypto";
|
|
2
2
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
3
3
|
import { dirname, join } from "path";
|
|
4
|
-
import type { ConversationRepository } from "
|
|
4
|
+
import type { ConversationRepository } from "./conversation.repository.js";
|
|
5
5
|
import type {
|
|
6
6
|
ConversationChunk,
|
|
7
7
|
ConversationHybridRow,
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
ParsedMessage,
|
|
11
11
|
SessionFileInfo,
|
|
12
12
|
SessionIndexDetail,
|
|
13
|
-
} from "
|
|
13
|
+
} from "./conversation.js";
|
|
14
14
|
import type { ConversationHistoryConfig } from "../config/index.js";
|
|
15
15
|
import { resolveSessionLogPath } from "../config/index.js";
|
|
16
16
|
import type { EmbeddingsService } from "./embeddings.service.js";
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as ort from "onnxruntime-node";
|
|
2
|
+
import { Tokenizer } from "@huggingface/tokenizers";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import { mkdir } from "fs/promises";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
|
|
7
|
+
const HF_CDN = "https://huggingface.co";
|
|
8
|
+
const MAX_SEQ_LENGTH = 512;
|
|
9
|
+
|
|
10
|
+
export class EmbeddingsService {
|
|
11
|
+
private modelName: string;
|
|
12
|
+
private session: ort.InferenceSession | null = null;
|
|
13
|
+
private tokenizer: Tokenizer | null = null;
|
|
14
|
+
private initPromise: Promise<void> | null = null;
|
|
15
|
+
private _dimension: number;
|
|
16
|
+
|
|
17
|
+
constructor(modelName: string, dimension: number) {
|
|
18
|
+
this.modelName = modelName;
|
|
19
|
+
this._dimension = dimension;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get dimension(): number {
|
|
23
|
+
return this._dimension;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private async initialize(): Promise<void> {
|
|
27
|
+
if (this.session) return;
|
|
28
|
+
if (!this.initPromise) {
|
|
29
|
+
this.initPromise = this._init();
|
|
30
|
+
}
|
|
31
|
+
await this.initPromise;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private get cacheDir(): string {
|
|
35
|
+
const packageRoot = join(dirname(Bun.main), "..");
|
|
36
|
+
return join(packageRoot, ".cache", "models", this.modelName);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private async downloadIfMissing(fileName: string): Promise<string> {
|
|
40
|
+
const filePath = join(this.cacheDir, fileName);
|
|
41
|
+
if (existsSync(filePath)) return filePath;
|
|
42
|
+
|
|
43
|
+
const url = `${HF_CDN}/${this.modelName}/resolve/main/${fileName}`;
|
|
44
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
45
|
+
const response = await fetch(url);
|
|
46
|
+
if (!response.ok) throw new Error(`Failed to download ${url}: ${response.status}`);
|
|
47
|
+
const buffer = await response.arrayBuffer();
|
|
48
|
+
await Bun.write(filePath, buffer);
|
|
49
|
+
return filePath;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private async _init(): Promise<void> {
|
|
53
|
+
const modelPath = await this.downloadIfMissing("onnx/model.onnx");
|
|
54
|
+
const tokenizerJsonPath = await this.downloadIfMissing("tokenizer.json");
|
|
55
|
+
const tokenizerConfigPath = await this.downloadIfMissing("tokenizer_config.json");
|
|
56
|
+
|
|
57
|
+
this.session = await ort.InferenceSession.create(modelPath, {
|
|
58
|
+
executionProviders: ["cpu"],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const tokenizerJson = await Bun.file(tokenizerJsonPath).json();
|
|
62
|
+
const tokenizerConfig = await Bun.file(tokenizerConfigPath).json();
|
|
63
|
+
this.tokenizer = new Tokenizer(tokenizerJson, tokenizerConfig);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async embed(text: string): Promise<number[]> {
|
|
67
|
+
await this.initialize();
|
|
68
|
+
|
|
69
|
+
const encoded = this.tokenizer!.encode(text);
|
|
70
|
+
|
|
71
|
+
// Truncate to model's max sequence length
|
|
72
|
+
const seqLen = Math.min(encoded.ids.length, MAX_SEQ_LENGTH);
|
|
73
|
+
const ids = encoded.ids.slice(0, seqLen);
|
|
74
|
+
const mask = encoded.attention_mask.slice(0, seqLen);
|
|
75
|
+
|
|
76
|
+
const inputIds = BigInt64Array.from(ids.map(BigInt));
|
|
77
|
+
const attentionMask = BigInt64Array.from(mask.map(BigInt));
|
|
78
|
+
const tokenTypeIds = new BigInt64Array(seqLen); // zeros for single-sequence input
|
|
79
|
+
|
|
80
|
+
const feeds: Record<string, ort.Tensor> = {
|
|
81
|
+
input_ids: new ort.Tensor("int64", inputIds, [1, seqLen]),
|
|
82
|
+
attention_mask: new ort.Tensor("int64", attentionMask, [1, seqLen]),
|
|
83
|
+
token_type_ids: new ort.Tensor("int64", tokenTypeIds, [1, seqLen]),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const output = await this.session!.run(feeds);
|
|
87
|
+
const lastHidden = output["last_hidden_state"];
|
|
88
|
+
|
|
89
|
+
const pooled = this.meanPool(lastHidden.data as Float32Array, mask, seqLen);
|
|
90
|
+
return this.normalize(pooled);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async embedBatch(texts: string[]): Promise<number[][]> {
|
|
94
|
+
const results: number[][] = [];
|
|
95
|
+
for (const text of texts) {
|
|
96
|
+
results.push(await this.embed(text));
|
|
97
|
+
}
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private meanPool(data: Float32Array, mask: number[], seqLen: number): number[] {
|
|
102
|
+
const dim = this._dimension;
|
|
103
|
+
const pooled = new Array(dim).fill(0);
|
|
104
|
+
let maskSum = 0;
|
|
105
|
+
for (let t = 0; t < seqLen; t++) {
|
|
106
|
+
if (mask[t]) {
|
|
107
|
+
maskSum += 1;
|
|
108
|
+
for (let d = 0; d < dim; d++) {
|
|
109
|
+
pooled[d] += data[t * dim + d];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (let d = 0; d < dim; d++) {
|
|
114
|
+
pooled[d] /= maskSum;
|
|
115
|
+
}
|
|
116
|
+
return pooled;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private normalize(vec: number[]): number[] {
|
|
120
|
+
let norm = 0;
|
|
121
|
+
for (const v of vec) norm += v * v;
|
|
122
|
+
norm = Math.sqrt(norm);
|
|
123
|
+
return vec.map(v => v / norm);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -12,11 +12,15 @@ import {
|
|
|
12
12
|
type Memory,
|
|
13
13
|
type HybridRow,
|
|
14
14
|
DELETED_TOMBSTONE,
|
|
15
|
-
} from "
|
|
15
|
+
} from "./memory.js";
|
|
16
16
|
|
|
17
17
|
export class MemoryRepository {
|
|
18
18
|
constructor(private db: Database) {}
|
|
19
19
|
|
|
20
|
+
getDb(): Database {
|
|
21
|
+
return this.db;
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
// ---------------------------------------------------------------------------
|
|
21
25
|
// Row mapping
|
|
22
26
|
// ---------------------------------------------------------------------------
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { randomUUID, createHash } from "crypto";
|
|
2
|
-
import type { Memory, SearchIntent, IntentProfile, HybridRow } from "
|
|
3
|
-
import { isDeleted } from "
|
|
4
|
-
import type { SearchResult, SearchOptions } from "
|
|
5
|
-
import type { MemoryRepository } from "
|
|
2
|
+
import type { Memory, SearchIntent, IntentProfile, HybridRow } from "./memory.js";
|
|
3
|
+
import { isDeleted } from "./memory.js";
|
|
4
|
+
import type { SearchResult, SearchOptions } from "./conversation.js";
|
|
5
|
+
import type { MemoryRepository } from "./memory.repository.js";
|
|
6
6
|
import type { EmbeddingsService } from "./embeddings.service.js";
|
|
7
7
|
import type { ConversationHistoryService } from "./conversation.service.js";
|
|
8
8
|
|
|
@@ -32,6 +32,14 @@ export class MemoryService {
|
|
|
32
32
|
return this.conversationService;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
getRepository(): MemoryRepository {
|
|
36
|
+
return this.repository;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getEmbeddings(): EmbeddingsService {
|
|
40
|
+
return this.embeddings;
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
async store(
|
|
36
44
|
content: string,
|
|
37
45
|
metadata: Record<string, unknown> = {},
|
|
@@ -366,6 +374,14 @@ ${list(args.memory_ids)}`;
|
|
|
366
374
|
};
|
|
367
375
|
|
|
368
376
|
await this.repository.upsert(memory);
|
|
377
|
+
|
|
378
|
+
// Always update the global (no-project) waypoint so the session-start
|
|
379
|
+
// hook can find the most recent waypoint without knowing the project name.
|
|
380
|
+
const globalId = MemoryService.UUID_ZERO;
|
|
381
|
+
if (memory.id !== globalId) {
|
|
382
|
+
await this.repository.upsert({ ...memory, id: globalId });
|
|
383
|
+
}
|
|
384
|
+
|
|
369
385
|
return memory;
|
|
370
386
|
}
|
|
371
387
|
|