memory-lancedb-pro 1.0.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/README.md +489 -0
- package/README_CN.md +406 -0
- package/cli.ts +611 -0
- package/index.ts +698 -0
- package/openclaw.plugin.json +385 -0
- package/package.json +38 -0
- package/skills/lesson/SKILL.md +28 -0
- package/src/adaptive-retrieval.ts +60 -0
- package/src/embedder.ts +354 -0
- package/src/migrate.ts +356 -0
- package/src/noise-filter.ts +78 -0
- package/src/retriever.ts +722 -0
- package/src/scopes.ts +374 -0
- package/src/store.ts +567 -0
- package/src/tools.ts +639 -0
package/src/scopes.ts
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Scope Access Control System
|
|
3
|
+
* Manages memory isolation and access permissions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Types & Configuration
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
export interface ScopeDefinition {
|
|
11
|
+
description: string;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ScopeConfig {
|
|
16
|
+
default: string;
|
|
17
|
+
definitions: Record<string, ScopeDefinition>;
|
|
18
|
+
agentAccess: Record<string, string[]>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ScopeManager {
|
|
22
|
+
getAccessibleScopes(agentId?: string): string[];
|
|
23
|
+
getDefaultScope(agentId?: string): string;
|
|
24
|
+
isAccessible(scope: string, agentId?: string): boolean;
|
|
25
|
+
validateScope(scope: string): boolean;
|
|
26
|
+
getAllScopes(): string[];
|
|
27
|
+
getScopeDefinition(scope: string): ScopeDefinition | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Default Configuration
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
export const DEFAULT_SCOPE_CONFIG: ScopeConfig = {
|
|
35
|
+
default: "global",
|
|
36
|
+
definitions: {
|
|
37
|
+
global: {
|
|
38
|
+
description: "Shared knowledge across all agents",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
agentAccess: {},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Built-in Scope Patterns
|
|
46
|
+
// ============================================================================
|
|
47
|
+
|
|
48
|
+
const SCOPE_PATTERNS = {
|
|
49
|
+
GLOBAL: "global",
|
|
50
|
+
AGENT: (agentId: string) => `agent:${agentId}`,
|
|
51
|
+
CUSTOM: (name: string) => `custom:${name}`,
|
|
52
|
+
PROJECT: (projectId: string) => `project:${projectId}`,
|
|
53
|
+
USER: (userId: string) => `user:${userId}`,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Scope Manager Implementation
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
export class MemoryScopeManager implements ScopeManager {
|
|
61
|
+
private config: ScopeConfig;
|
|
62
|
+
|
|
63
|
+
constructor(config: Partial<ScopeConfig> = {}) {
|
|
64
|
+
this.config = {
|
|
65
|
+
default: config.default || DEFAULT_SCOPE_CONFIG.default,
|
|
66
|
+
definitions: {
|
|
67
|
+
...DEFAULT_SCOPE_CONFIG.definitions,
|
|
68
|
+
...config.definitions,
|
|
69
|
+
},
|
|
70
|
+
agentAccess: {
|
|
71
|
+
...DEFAULT_SCOPE_CONFIG.agentAccess,
|
|
72
|
+
...config.agentAccess,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Ensure global scope always exists
|
|
77
|
+
if (!this.config.definitions.global) {
|
|
78
|
+
this.config.definitions.global = {
|
|
79
|
+
description: "Shared knowledge across all agents",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.validateConfiguration();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private validateConfiguration(): void {
|
|
87
|
+
// Validate default scope exists in definitions
|
|
88
|
+
if (!this.config.definitions[this.config.default]) {
|
|
89
|
+
throw new Error(`Default scope '${this.config.default}' not found in definitions`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Validate agent access scopes exist in definitions
|
|
93
|
+
for (const [agentId, scopes] of Object.entries(this.config.agentAccess)) {
|
|
94
|
+
for (const scope of scopes) {
|
|
95
|
+
if (!this.config.definitions[scope] && !this.isBuiltInScope(scope)) {
|
|
96
|
+
console.warn(`Agent '${agentId}' has access to undefined scope '${scope}'`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private isBuiltInScope(scope: string): boolean {
|
|
103
|
+
return (
|
|
104
|
+
scope === "global" ||
|
|
105
|
+
scope.startsWith("agent:") ||
|
|
106
|
+
scope.startsWith("custom:") ||
|
|
107
|
+
scope.startsWith("project:") ||
|
|
108
|
+
scope.startsWith("user:")
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getAccessibleScopes(agentId?: string): string[] {
|
|
113
|
+
if (!agentId) {
|
|
114
|
+
// No agent specified, return all scopes
|
|
115
|
+
return this.getAllScopes();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Check explicit agent access configuration
|
|
119
|
+
const explicitAccess = this.config.agentAccess[agentId];
|
|
120
|
+
if (explicitAccess) {
|
|
121
|
+
return explicitAccess;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Default access: global + agent-specific scope
|
|
125
|
+
const defaultScopes = ["global"];
|
|
126
|
+
const agentScope = SCOPE_PATTERNS.AGENT(agentId);
|
|
127
|
+
|
|
128
|
+
// Only include agent scope if it already exists — don't mutate config as a side effect
|
|
129
|
+
if (this.config.definitions[agentScope] || this.isBuiltInScope(agentScope)) {
|
|
130
|
+
defaultScopes.push(agentScope);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return defaultScopes;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
getDefaultScope(agentId?: string): string {
|
|
137
|
+
if (!agentId) {
|
|
138
|
+
return this.config.default;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// For agents, default to their private scope if they have access to it
|
|
142
|
+
const agentScope = SCOPE_PATTERNS.AGENT(agentId);
|
|
143
|
+
const accessibleScopes = this.getAccessibleScopes(agentId);
|
|
144
|
+
|
|
145
|
+
if (accessibleScopes.includes(agentScope)) {
|
|
146
|
+
return agentScope;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return this.config.default;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
isAccessible(scope: string, agentId?: string): boolean {
|
|
153
|
+
if (!agentId) {
|
|
154
|
+
// No agent specified, allow access to all valid scopes
|
|
155
|
+
return this.validateScope(scope);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const accessibleScopes = this.getAccessibleScopes(agentId);
|
|
159
|
+
return accessibleScopes.includes(scope);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
validateScope(scope: string): boolean {
|
|
163
|
+
if (!scope || typeof scope !== "string" || scope.trim().length === 0) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const trimmedScope = scope.trim();
|
|
168
|
+
|
|
169
|
+
// Check if scope is defined or is a built-in pattern
|
|
170
|
+
return (
|
|
171
|
+
this.config.definitions[trimmedScope] !== undefined ||
|
|
172
|
+
this.isBuiltInScope(trimmedScope)
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getAllScopes(): string[] {
|
|
177
|
+
return Object.keys(this.config.definitions);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
getScopeDefinition(scope: string): ScopeDefinition | undefined {
|
|
181
|
+
return this.config.definitions[scope];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Management methods
|
|
185
|
+
|
|
186
|
+
addScopeDefinition(scope: string, definition: ScopeDefinition): void {
|
|
187
|
+
if (!this.validateScopeFormat(scope)) {
|
|
188
|
+
throw new Error(`Invalid scope format: ${scope}`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.config.definitions[scope] = definition;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
removeScopeDefinition(scope: string): boolean {
|
|
195
|
+
if (scope === "global") {
|
|
196
|
+
throw new Error("Cannot remove global scope");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!this.config.definitions[scope]) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
delete this.config.definitions[scope];
|
|
204
|
+
|
|
205
|
+
// Clean up agent access references
|
|
206
|
+
for (const [agentId, scopes] of Object.entries(this.config.agentAccess)) {
|
|
207
|
+
const filtered = scopes.filter(s => s !== scope);
|
|
208
|
+
if (filtered.length !== scopes.length) {
|
|
209
|
+
this.config.agentAccess[agentId] = filtered;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
setAgentAccess(agentId: string, scopes: string[]): void {
|
|
217
|
+
if (!agentId || typeof agentId !== "string") {
|
|
218
|
+
throw new Error("Invalid agent ID");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Validate all scopes
|
|
222
|
+
for (const scope of scopes) {
|
|
223
|
+
if (!this.validateScope(scope)) {
|
|
224
|
+
throw new Error(`Invalid scope: ${scope}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
this.config.agentAccess[agentId] = [...scopes];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
removeAgentAccess(agentId: string): boolean {
|
|
232
|
+
if (!this.config.agentAccess[agentId]) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
delete this.config.agentAccess[agentId];
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private validateScopeFormat(scope: string): boolean {
|
|
241
|
+
if (!scope || typeof scope !== "string") {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const trimmed = scope.trim();
|
|
246
|
+
|
|
247
|
+
// Basic format validation
|
|
248
|
+
if (trimmed.length === 0 || trimmed.length > 100) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Allow alphanumeric, hyphens, underscores, colons, and dots
|
|
253
|
+
const validFormat = /^[a-zA-Z0-9._:-]+$/.test(trimmed);
|
|
254
|
+
return validFormat;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Export/Import configuration
|
|
258
|
+
|
|
259
|
+
exportConfig(): ScopeConfig {
|
|
260
|
+
return JSON.parse(JSON.stringify(this.config));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
importConfig(config: Partial<ScopeConfig>): void {
|
|
264
|
+
this.config = {
|
|
265
|
+
default: config.default || this.config.default,
|
|
266
|
+
definitions: {
|
|
267
|
+
...this.config.definitions,
|
|
268
|
+
...config.definitions,
|
|
269
|
+
},
|
|
270
|
+
agentAccess: {
|
|
271
|
+
...this.config.agentAccess,
|
|
272
|
+
...config.agentAccess,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
this.validateConfiguration();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Statistics
|
|
280
|
+
|
|
281
|
+
getStats(): {
|
|
282
|
+
totalScopes: number;
|
|
283
|
+
agentsWithCustomAccess: number;
|
|
284
|
+
scopesByType: Record<string, number>;
|
|
285
|
+
} {
|
|
286
|
+
const scopes = this.getAllScopes();
|
|
287
|
+
const scopesByType: Record<string, number> = {
|
|
288
|
+
global: 0,
|
|
289
|
+
agent: 0,
|
|
290
|
+
custom: 0,
|
|
291
|
+
project: 0,
|
|
292
|
+
user: 0,
|
|
293
|
+
other: 0,
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
for (const scope of scopes) {
|
|
297
|
+
if (scope === "global") {
|
|
298
|
+
scopesByType.global++;
|
|
299
|
+
} else if (scope.startsWith("agent:")) {
|
|
300
|
+
scopesByType.agent++;
|
|
301
|
+
} else if (scope.startsWith("custom:")) {
|
|
302
|
+
scopesByType.custom++;
|
|
303
|
+
} else if (scope.startsWith("project:")) {
|
|
304
|
+
scopesByType.project++;
|
|
305
|
+
} else if (scope.startsWith("user:")) {
|
|
306
|
+
scopesByType.user++;
|
|
307
|
+
} else {
|
|
308
|
+
scopesByType.other++;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
totalScopes: scopes.length,
|
|
314
|
+
agentsWithCustomAccess: Object.keys(this.config.agentAccess).length,
|
|
315
|
+
scopesByType,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ============================================================================
|
|
321
|
+
// Factory Functions
|
|
322
|
+
// ============================================================================
|
|
323
|
+
|
|
324
|
+
export function createScopeManager(config?: Partial<ScopeConfig>): MemoryScopeManager {
|
|
325
|
+
return new MemoryScopeManager(config);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export function createAgentScope(agentId: string): string {
|
|
329
|
+
return SCOPE_PATTERNS.AGENT(agentId);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export function createCustomScope(name: string): string {
|
|
333
|
+
return SCOPE_PATTERNS.CUSTOM(name);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export function createProjectScope(projectId: string): string {
|
|
337
|
+
return SCOPE_PATTERNS.PROJECT(projectId);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export function createUserScope(userId: string): string {
|
|
341
|
+
return SCOPE_PATTERNS.USER(userId);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ============================================================================
|
|
345
|
+
// Utility Functions
|
|
346
|
+
// ============================================================================
|
|
347
|
+
|
|
348
|
+
export function parseScopeId(scope: string): { type: string; id: string } | null {
|
|
349
|
+
if (scope === "global") {
|
|
350
|
+
return { type: "global", id: "" };
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const colonIndex = scope.indexOf(":");
|
|
354
|
+
if (colonIndex === -1) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
type: scope.substring(0, colonIndex),
|
|
360
|
+
id: scope.substring(colonIndex + 1),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function isScopeAccessible(scope: string, allowedScopes: string[]): boolean {
|
|
365
|
+
return allowedScopes.includes(scope);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export function filterScopesForAgent(scopes: string[], agentId?: string, scopeManager?: ScopeManager): string[] {
|
|
369
|
+
if (!scopeManager || !agentId) {
|
|
370
|
+
return scopes;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return scopes.filter(scope => scopeManager.isAccessible(scope, agentId));
|
|
374
|
+
}
|