@prmichaelsen/remember-mcp 3.15.7 → 3.16.2
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/.github/workflows/publish.yml +55 -0
- package/CHANGELOG.md +20 -0
- package/agent/design/local.unified-internal-memory-tools.md +325 -0
- package/agent/milestones/milestone-20-unified-internal-memory-tools.md +58 -0
- package/agent/progress.yaml +115 -1
- package/agent/tasks/milestone-20-unified-internal-memory-tools/task-212-add-internal-context-type.md +54 -0
- package/agent/tasks/milestone-20-unified-internal-memory-tools/task-213-update-server-factory-internal-context.md +117 -0
- package/agent/tasks/milestone-20-unified-internal-memory-tools/task-214-create-tag-builder-utility.md +50 -0
- package/agent/tasks/milestone-20-unified-internal-memory-tools/task-215-create-unified-internal-memory-tools.md +65 -0
- package/agent/tasks/milestone-20-unified-internal-memory-tools/task-216-update-default-search-filters.md +46 -0
- package/agent/tasks/milestone-20-unified-internal-memory-tools/task-217-delete-standalone-ghost-tools.md +46 -0
- package/agent/tasks/milestone-20-unified-internal-memory-tools/task-218-add-tests-unified-internal-tools.md +66 -0
- package/dist/e2e-helpers.d.ts +1 -1
- package/dist/server-factory.d.ts +17 -41
- package/dist/server-factory.js +420 -149
- package/dist/server.js +202 -20
- package/dist/tools/{create-ghost-memory.d.ts → create-internal-memory.d.ts} +7 -9
- package/dist/tools/internal-tools.spec.d.ts +2 -0
- package/dist/tools/{query-ghost-memory.d.ts → query-internal-memory.d.ts} +6 -6
- package/dist/tools/{search-ghost-memory-by.d.ts → search-internal-memory-by.d.ts} +6 -6
- package/dist/tools/{search-ghost-memory.d.ts → search-internal-memory.d.ts} +6 -6
- package/dist/tools/{update-ghost-memory.d.ts → update-internal-memory.d.ts} +6 -6
- package/dist/types/auth.d.ts +22 -8
- package/dist/utils/internal-tags.d.ts +14 -0
- package/dist/utils/internal-tags.spec.d.ts +2 -0
- package/package.json +2 -3
- package/src/e2e-helpers.ts +4 -2
- package/src/ghost-persona.e2e.ts +18 -17
- package/src/server-factory.ts +117 -55
- package/src/tools/create-internal-memory.ts +105 -0
- package/src/tools/find-similar.ts +2 -2
- package/src/tools/internal-tools.spec.ts +312 -0
- package/src/tools/query-internal-memory.ts +73 -0
- package/src/tools/query-memory.ts +15 -12
- package/src/tools/search-by.spec.ts +6 -2
- package/src/tools/search-by.ts +6 -6
- package/src/tools/{search-ghost-memory-by.ts → search-internal-memory-by.ts} +34 -27
- package/src/tools/search-internal-memory.ts +87 -0
- package/src/tools/search-memory.ts +15 -12
- package/src/tools/search-space.ts +1 -0
- package/src/tools/{update-ghost-memory.ts → update-internal-memory.ts} +23 -17
- package/src/types/auth.ts +22 -8
- package/src/utils/internal-tags.spec.ts +104 -0
- package/src/utils/internal-tags.ts +46 -0
- package/dist/tools/ghost-tools.spec.d.ts +0 -2
- package/src/tools/create-ghost-memory.ts +0 -103
- package/src/tools/ghost-tools.spec.ts +0 -361
- package/src/tools/query-ghost-memory.ts +0 -63
- package/src/tools/search-ghost-memory.ts +0 -73
package/src/ghost-persona.e2e.ts
CHANGED
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
e2eEnsureCollection, e2eCleanup, parseResult, waitForIndex,
|
|
11
11
|
} from './e2e-helpers.js';
|
|
12
12
|
import { handleGhostConfig } from './tools/ghost-config.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
13
|
+
import { handleCreateInternalMemory } from './tools/create-internal-memory.js';
|
|
14
|
+
import { handleSearchInternalMemory } from './tools/search-internal-memory.js';
|
|
15
|
+
import { handleUpdateInternalMemory } from './tools/update-internal-memory.js';
|
|
16
|
+
import { handleQueryInternalMemory } from './tools/query-internal-memory.js';
|
|
17
|
+
import { handleSearchInternalMemoryBy } from './tools/search-internal-memory-by.js';
|
|
18
18
|
import { handleGetCore } from './tools/get-core.js';
|
|
19
19
|
|
|
20
20
|
const ownerId = e2eUserId('ghost_owner');
|
|
@@ -79,7 +79,7 @@ describe('E2E: Ghost/Persona', () => {
|
|
|
79
79
|
// -------------------------------------------------------------------------
|
|
80
80
|
|
|
81
81
|
it('creates a ghost memory', async () => {
|
|
82
|
-
const res = parseResult(await
|
|
82
|
+
const res = parseResult(await handleCreateInternalMemory(
|
|
83
83
|
{
|
|
84
84
|
content: `${accessorId} asked about my favorite hiking trails. They seem genuinely interested in outdoor activities.`,
|
|
85
85
|
weight: 0.6,
|
|
@@ -94,7 +94,8 @@ describe('E2E: Ghost/Persona', () => {
|
|
|
94
94
|
expect(res.memory_id).toBeTruthy();
|
|
95
95
|
expect(res.content_type).toBe('ghost');
|
|
96
96
|
expect(res.tags).toContain('ghost');
|
|
97
|
-
expect(res.tags).toContain(
|
|
97
|
+
expect(res.tags).toContain('ghost_type:user');
|
|
98
|
+
expect(res.tags).toContain(`ghost_owner:user:${ownerId}`);
|
|
98
99
|
ghostMemoryId = res.memory_id;
|
|
99
100
|
console.log(` created ghost memory ${ghostMemoryId}`);
|
|
100
101
|
});
|
|
@@ -106,10 +107,10 @@ describe('E2E: Ghost/Persona', () => {
|
|
|
106
107
|
it('searches ghost memories', async () => {
|
|
107
108
|
await waitForIndex(5000);
|
|
108
109
|
|
|
109
|
-
// Search ghost memories
|
|
110
|
-
const res = parseResult(await
|
|
110
|
+
// Search ghost memories via unified internal tool
|
|
111
|
+
const res = parseResult(await handleSearchInternalMemory(
|
|
111
112
|
{ query: 'hiking trails outdoor activities', limit: 5 },
|
|
112
|
-
ownerId,
|
|
113
|
+
ownerId, ghostAuth,
|
|
113
114
|
));
|
|
114
115
|
|
|
115
116
|
expect(res.memories).toBeDefined();
|
|
@@ -123,7 +124,7 @@ describe('E2E: Ghost/Persona', () => {
|
|
|
123
124
|
// -------------------------------------------------------------------------
|
|
124
125
|
|
|
125
126
|
it('updates the ghost memory', async () => {
|
|
126
|
-
const res = parseResult(await
|
|
127
|
+
const res = parseResult(await handleUpdateInternalMemory(
|
|
127
128
|
{
|
|
128
129
|
memory_id: ghostMemoryId,
|
|
129
130
|
content: `${accessorId} asked about my favorite hiking trails. They seem genuinely interested in outdoor activities. Follow-up: they mentioned they go rock climbing too.`,
|
|
@@ -141,10 +142,10 @@ describe('E2E: Ghost/Persona', () => {
|
|
|
141
142
|
it('queries ghost memories with natural language', async () => {
|
|
142
143
|
await waitForIndex();
|
|
143
144
|
|
|
144
|
-
// Use
|
|
145
|
-
const res = parseResult(await
|
|
145
|
+
// Use ghostAuth — query is auto-scoped to ghost content_type via internal context
|
|
146
|
+
const res = parseResult(await handleQueryInternalMemory(
|
|
146
147
|
{ query: 'What are the accessor\'s outdoor interests?', limit: 5, min_relevance: 0.3 },
|
|
147
|
-
ownerId,
|
|
148
|
+
ownerId, ghostAuth,
|
|
148
149
|
));
|
|
149
150
|
|
|
150
151
|
expect(res.memories).toBeDefined();
|
|
@@ -160,10 +161,10 @@ describe('E2E: Ghost/Persona', () => {
|
|
|
160
161
|
// This creates an impossible filter: content_type='ghost' AND content_type!='ghost'.
|
|
161
162
|
// Fix: core should skip ghost exclusion when types filter explicitly includes 'ghost'.
|
|
162
163
|
// This test WILL FAIL until the core bug is fixed.
|
|
163
|
-
it('
|
|
164
|
-
const res = parseResult(await
|
|
164
|
+
it('search_internal_memory_by byTime returns ghost results', async () => {
|
|
165
|
+
const res = parseResult(await handleSearchInternalMemoryBy(
|
|
165
166
|
{ mode: 'byTime', limit: 5 },
|
|
166
|
-
ownerId,
|
|
167
|
+
ownerId, ghostAuth,
|
|
167
168
|
));
|
|
168
169
|
|
|
169
170
|
expect(res.memories).toBeDefined();
|
package/src/server-factory.ts
CHANGED
|
@@ -46,12 +46,12 @@ import { moderateTool, handleModerate } from './tools/moderate.js';
|
|
|
46
46
|
import { ghostConfigTool, handleGhostConfig } from './tools/ghost-config.js';
|
|
47
47
|
import { searchByTool, handleSearchBy } from './tools/search-by.js';
|
|
48
48
|
|
|
49
|
-
// Import
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
49
|
+
// Import unified internal memory tools
|
|
50
|
+
import { createInternalMemoryTool, handleCreateInternalMemory } from './tools/create-internal-memory.js';
|
|
51
|
+
import { updateInternalMemoryTool, handleUpdateInternalMemory } from './tools/update-internal-memory.js';
|
|
52
|
+
import { searchInternalMemoryTool, handleSearchInternalMemory } from './tools/search-internal-memory.js';
|
|
53
|
+
import { queryInternalMemoryTool, handleQueryInternalMemory } from './tools/query-internal-memory.js';
|
|
54
|
+
import { searchInternalMemoryByTool, handleSearchInternalMemoryBy } from './tools/search-internal-memory-by.js';
|
|
55
55
|
|
|
56
56
|
// Import core introspection tools
|
|
57
57
|
import { getCoreTool, handleGetCore } from './tools/get-core.js';
|
|
@@ -65,18 +65,25 @@ export interface ServerOptions {
|
|
|
65
65
|
name?: string;
|
|
66
66
|
version?: string;
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* - Trust filtering is applied based on the accessor's trust level
|
|
71
|
-
* - Trust level is resolved server-side from GhostConfig (Firestore)
|
|
68
|
+
* Internal context for ghost/agent sessions. When set, the server provides
|
|
69
|
+
* unified internal memory tools with behavior driven by the context type.
|
|
72
70
|
*
|
|
73
|
-
*
|
|
71
|
+
* Populated from platform HTTP headers via mcp-auth extras:
|
|
72
|
+
* X-Internal-Type → type ('ghost' | 'agent')
|
|
73
|
+
* X-Ghost-Owner → owner_user_id
|
|
74
|
+
* X-Ghost-Type → ghost_type ('user' | 'space' | 'group')
|
|
75
|
+
* X-Ghost-Space → ghost_space
|
|
76
|
+
* X-Ghost-Group → ghost_group
|
|
77
|
+
*
|
|
78
|
+
* Trust level is resolved server-side from GhostConfig (Firestore).
|
|
74
79
|
* The LLM never has access to set or override these values.
|
|
75
80
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
internalContext?: {
|
|
82
|
+
type: 'ghost' | 'agent';
|
|
83
|
+
ghost_type?: 'user' | 'space' | 'group';
|
|
84
|
+
ghost_space?: string;
|
|
85
|
+
ghost_group?: string;
|
|
86
|
+
owner_user_id?: string;
|
|
80
87
|
accessor_user_id: string;
|
|
81
88
|
};
|
|
82
89
|
}
|
|
@@ -157,29 +164,72 @@ async function ensureDatabasesInitialized(): Promise<void> {
|
|
|
157
164
|
* });
|
|
158
165
|
* ```
|
|
159
166
|
*/
|
|
167
|
+
/**
|
|
168
|
+
* Normalize flat mcp-auth extras into structured ServerOptions.
|
|
169
|
+
*
|
|
170
|
+
* mcp-auth strips X- prefix and converts hyphens to underscores:
|
|
171
|
+
* X-Internal-Type → internal_type
|
|
172
|
+
* X-Ghost-Owner → ghost_owner
|
|
173
|
+
* X-Ghost-Type → ghost_type
|
|
174
|
+
* X-Ghost-Space → ghost_space
|
|
175
|
+
* X-Ghost-Group → ghost_group
|
|
176
|
+
*/
|
|
177
|
+
function normalizeOptions(
|
|
178
|
+
raw: ServerOptions | Record<string, string | string[] | undefined>,
|
|
179
|
+
userId: string
|
|
180
|
+
): ServerOptions {
|
|
181
|
+
// Already structured — has internalContext or no internal_type key
|
|
182
|
+
if ('internalContext' in raw || !('internal_type' in raw)) {
|
|
183
|
+
return raw as ServerOptions;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Flat extras from mcp-auth
|
|
187
|
+
const extras = raw as Record<string, string | string[] | undefined>;
|
|
188
|
+
const internalType = extras.internal_type as string | undefined;
|
|
189
|
+
|
|
190
|
+
if (!internalType) {
|
|
191
|
+
return {};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
internalContext: {
|
|
196
|
+
type: internalType as 'ghost' | 'agent',
|
|
197
|
+
ghost_type: extras.ghost_type as 'user' | 'space' | 'group' | undefined,
|
|
198
|
+
ghost_space: extras.ghost_space as string | undefined,
|
|
199
|
+
ghost_group: extras.ghost_group as string | undefined,
|
|
200
|
+
owner_user_id: extras.ghost_owner as string | undefined,
|
|
201
|
+
accessor_user_id: userId,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
160
206
|
export async function createServer(
|
|
161
207
|
accessToken: string,
|
|
162
208
|
userId: string,
|
|
163
|
-
options: ServerOptions = {}
|
|
209
|
+
options: ServerOptions | Record<string, string | string[] | undefined> = {}
|
|
164
210
|
): Promise<Server> {
|
|
165
211
|
// Note: accessToken is not used by remember-mcp (self-managed data)
|
|
166
212
|
// but required by mcp-auth contract. Can be any value including empty string.
|
|
167
|
-
|
|
213
|
+
|
|
168
214
|
if (!userId) {
|
|
169
215
|
throw new Error('userId is required');
|
|
170
216
|
}
|
|
171
|
-
|
|
217
|
+
|
|
218
|
+
// Normalize: mcp-auth passes flat extras (e.g. { internal_type: 'ghost', ghost_owner: 'alice' })
|
|
219
|
+
// Direct callers pass structured ServerOptions (e.g. { internalContext: { type: 'ghost', ... } })
|
|
220
|
+
const opts = normalizeOptions(options, userId);
|
|
221
|
+
|
|
172
222
|
logger.debug('Creating server instance', { userId });
|
|
173
|
-
|
|
223
|
+
|
|
174
224
|
// Ensure databases are initialized (happens once globally)
|
|
175
225
|
// Initialization must succeed or server creation fails
|
|
176
226
|
await ensureDatabasesInitialized();
|
|
177
|
-
|
|
227
|
+
|
|
178
228
|
// Create MCP server
|
|
179
229
|
const server = new Server(
|
|
180
230
|
{
|
|
181
|
-
name:
|
|
182
|
-
version:
|
|
231
|
+
name: opts.name || 'remember-mcp',
|
|
232
|
+
version: opts.version || '0.2.0',
|
|
183
233
|
},
|
|
184
234
|
{
|
|
185
235
|
capabilities: {
|
|
@@ -187,26 +237,38 @@ export async function createServer(
|
|
|
187
237
|
},
|
|
188
238
|
}
|
|
189
239
|
);
|
|
190
|
-
|
|
191
|
-
// Resolve
|
|
192
|
-
let
|
|
193
|
-
if (
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
240
|
+
|
|
241
|
+
// Resolve internal context with trust level from Firestore if ghost mode
|
|
242
|
+
let resolvedInternalContext: import('./types/auth.js').InternalContext | undefined;
|
|
243
|
+
if (opts.internalContext) {
|
|
244
|
+
const ic = opts.internalContext;
|
|
245
|
+
let accessorTrustLevel: number | undefined;
|
|
246
|
+
|
|
247
|
+
if (ic.type === 'ghost' && ic.owner_user_id) {
|
|
248
|
+
const ghostConfig = await getGhostConfig(ic.owner_user_id);
|
|
249
|
+
accessorTrustLevel = await resolveAccessorTrustLevel(ghostConfig, ic.owner_user_id, ic.accessor_user_id);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
resolvedInternalContext = {
|
|
253
|
+
type: ic.type,
|
|
254
|
+
ghost_type: ic.ghost_type,
|
|
255
|
+
ghost_space: ic.ghost_space,
|
|
256
|
+
ghost_group: ic.ghost_group,
|
|
257
|
+
owner_user_id: ic.owner_user_id,
|
|
258
|
+
accessor_user_id: ic.accessor_user_id,
|
|
259
|
+
accessor_trust_level: accessorTrustLevel,
|
|
200
260
|
};
|
|
201
|
-
logger.info('
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
261
|
+
logger.info('Internal context resolved', {
|
|
262
|
+
type: resolvedInternalContext.type,
|
|
263
|
+
ghostType: resolvedInternalContext.ghost_type,
|
|
264
|
+
ownerUserId: resolvedInternalContext.owner_user_id,
|
|
265
|
+
accessorUserId: resolvedInternalContext.accessor_user_id,
|
|
266
|
+
trustLevel: resolvedInternalContext.accessor_trust_level,
|
|
205
267
|
});
|
|
206
268
|
}
|
|
207
269
|
|
|
208
270
|
// Register handlers with userId scope
|
|
209
|
-
registerHandlers(server, userId, accessToken,
|
|
271
|
+
registerHandlers(server, userId, accessToken, resolvedInternalContext);
|
|
210
272
|
|
|
211
273
|
return server;
|
|
212
274
|
}
|
|
@@ -218,7 +280,7 @@ function registerHandlers(
|
|
|
218
280
|
server: Server,
|
|
219
281
|
userId: string,
|
|
220
282
|
accessToken: string,
|
|
221
|
-
|
|
283
|
+
internalContext?: import('./types/auth.js').InternalContext
|
|
222
284
|
): void {
|
|
223
285
|
// List available tools
|
|
224
286
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -251,12 +313,12 @@ function registerHandlers(
|
|
|
251
313
|
ghostConfigTool,
|
|
252
314
|
// Search modes
|
|
253
315
|
searchByTool,
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
316
|
+
// Unified internal memory tools
|
|
317
|
+
createInternalMemoryTool,
|
|
318
|
+
updateInternalMemoryTool,
|
|
319
|
+
searchInternalMemoryTool,
|
|
320
|
+
queryInternalMemoryTool,
|
|
321
|
+
searchInternalMemoryByTool,
|
|
260
322
|
// Core introspection
|
|
261
323
|
getCoreTool,
|
|
262
324
|
// Space search modes
|
|
@@ -272,7 +334,7 @@ function registerHandlers(
|
|
|
272
334
|
try {
|
|
273
335
|
// Resolve credentials once per request
|
|
274
336
|
const credentials = await credentialsProvider.getCredentials(accessToken, userId);
|
|
275
|
-
const authContext: AuthContext = { accessToken, credentials,
|
|
337
|
+
const authContext: AuthContext = { accessToken, credentials, internalContext };
|
|
276
338
|
|
|
277
339
|
let result: string;
|
|
278
340
|
|
|
@@ -365,24 +427,24 @@ function registerHandlers(
|
|
|
365
427
|
result = await handleSearchBy(args as any, userId, authContext);
|
|
366
428
|
break;
|
|
367
429
|
|
|
368
|
-
case '
|
|
369
|
-
result = await
|
|
430
|
+
case 'remember_create_internal_memory':
|
|
431
|
+
result = await handleCreateInternalMemory(args as any, userId, authContext);
|
|
370
432
|
break;
|
|
371
433
|
|
|
372
|
-
case '
|
|
373
|
-
result = await
|
|
434
|
+
case 'remember_update_internal_memory':
|
|
435
|
+
result = await handleUpdateInternalMemory(args as any, userId, authContext);
|
|
374
436
|
break;
|
|
375
437
|
|
|
376
|
-
case '
|
|
377
|
-
result = await
|
|
438
|
+
case 'remember_search_internal_memory':
|
|
439
|
+
result = await handleSearchInternalMemory(args as any, userId, authContext);
|
|
378
440
|
break;
|
|
379
441
|
|
|
380
|
-
case '
|
|
381
|
-
result = await
|
|
442
|
+
case 'remember_query_internal_memory':
|
|
443
|
+
result = await handleQueryInternalMemory(args as any, userId, authContext);
|
|
382
444
|
break;
|
|
383
445
|
|
|
384
|
-
case '
|
|
385
|
-
result = await
|
|
446
|
+
case 'remember_search_internal_memory_by':
|
|
447
|
+
result = await handleSearchInternalMemoryBy(args as any, userId, authContext);
|
|
386
448
|
break;
|
|
387
449
|
|
|
388
450
|
case 'remember_get_core':
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remember_create_internal_memory tool
|
|
3
|
+
* Creates a ghost or agent memory based on the current session's InternalContext.
|
|
4
|
+
* Content type and tags are derived from platform HTTP headers, not tool args.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { handleToolError } from '../utils/error-handler.js';
|
|
8
|
+
import { createDebugLogger } from '../utils/debug.js';
|
|
9
|
+
import type { AuthContext } from '../types/auth.js';
|
|
10
|
+
import { createCoreServices } from '../core-services.js';
|
|
11
|
+
import { buildInternalTags } from '../utils/internal-tags.js';
|
|
12
|
+
|
|
13
|
+
export const createInternalMemoryTool = {
|
|
14
|
+
name: 'remember_create_internal_memory',
|
|
15
|
+
description: `Create an internal memory (ghost observation or agent note) based on the current session context.
|
|
16
|
+
|
|
17
|
+
In ghost mode: creates a ghost memory tracking conversation observations, impressions,
|
|
18
|
+
and insights. Automatically tagged with ghost source isolation tags.
|
|
19
|
+
|
|
20
|
+
In agent mode: creates an agent memory for AI observations and notes.
|
|
21
|
+
Automatically tagged with agent tags.
|
|
22
|
+
|
|
23
|
+
Content type and tags are determined by the platform session context.
|
|
24
|
+
This tool errors if no internal session context is present.`,
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
content: { type: 'string', description: 'Memory content' },
|
|
29
|
+
title: { type: 'string', description: 'Optional title' },
|
|
30
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Additional tags (internal tags added automatically)' },
|
|
31
|
+
weight: { type: 'number', minimum: 0, maximum: 1, description: 'Significance (0-1)' },
|
|
32
|
+
trust: { type: 'number', minimum: 0, maximum: 1, description: 'Trust level (0-1)' },
|
|
33
|
+
feel_salience: { type: 'number', minimum: 0, maximum: 1 },
|
|
34
|
+
feel_social_weight: { type: 'number', minimum: 0, maximum: 1 },
|
|
35
|
+
feel_narrative_importance: { type: 'number', minimum: 0, maximum: 1 },
|
|
36
|
+
},
|
|
37
|
+
required: ['content'],
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export interface CreateInternalMemoryArgs {
|
|
42
|
+
content: string;
|
|
43
|
+
title?: string;
|
|
44
|
+
tags?: string[];
|
|
45
|
+
weight?: number;
|
|
46
|
+
trust?: number;
|
|
47
|
+
[key: string]: any;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function handleCreateInternalMemory(
|
|
51
|
+
args: CreateInternalMemoryArgs,
|
|
52
|
+
userId: string,
|
|
53
|
+
authContext?: AuthContext
|
|
54
|
+
): Promise<string> {
|
|
55
|
+
const debug = createDebugLogger({ tool: 'remember_create_internal_memory', userId, operation: 'create internal memory' });
|
|
56
|
+
try {
|
|
57
|
+
debug.info('Tool invoked');
|
|
58
|
+
|
|
59
|
+
const ctx = authContext?.internalContext;
|
|
60
|
+
if (!ctx) {
|
|
61
|
+
return JSON.stringify({ error: 'Internal context required. X-Internal-Type header must be set.' });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { memory } = createCoreServices(userId);
|
|
65
|
+
|
|
66
|
+
// Build tags from internal context (ghost source isolation or agent)
|
|
67
|
+
const internalTags = buildInternalTags(authContext!);
|
|
68
|
+
const userTags = args.tags ?? [];
|
|
69
|
+
const mergedTags = [...new Set([...internalTags, ...userTags])];
|
|
70
|
+
|
|
71
|
+
// Extract feel_* fields
|
|
72
|
+
const feelFields: Record<string, number> = {};
|
|
73
|
+
for (const [key, value] of Object.entries(args)) {
|
|
74
|
+
if (key.startsWith('feel_') && typeof value === 'number') {
|
|
75
|
+
feelFields[key] = value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const result = await memory.create({
|
|
80
|
+
content: args.content,
|
|
81
|
+
title: args.title,
|
|
82
|
+
type: ctx.type as any,
|
|
83
|
+
weight: args.weight,
|
|
84
|
+
trust: args.trust,
|
|
85
|
+
tags: mergedTags,
|
|
86
|
+
context_summary: `Internal memory created via MCP (${ctx.type})`,
|
|
87
|
+
...feelFields,
|
|
88
|
+
} as any);
|
|
89
|
+
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
memory_id: result.memory_id,
|
|
92
|
+
created_at: result.created_at,
|
|
93
|
+
content_type: ctx.type,
|
|
94
|
+
tags: mergedTags,
|
|
95
|
+
message: `${ctx.type} memory created successfully with ID: ${result.memory_id}`,
|
|
96
|
+
}, null, 2);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
debug.error('Tool failed', { error: error instanceof Error ? error.message : String(error) });
|
|
99
|
+
handleToolError(error, {
|
|
100
|
+
toolName: 'remember_create_internal_memory',
|
|
101
|
+
operation: 'create internal memory',
|
|
102
|
+
userId,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -120,9 +120,9 @@ export async function handleFindSimilar(
|
|
|
120
120
|
deleted_filter: args.deleted_filter,
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
// Post-filter
|
|
123
|
+
// Post-filter internal content types (core doesn't exclude ghost/agent)
|
|
124
124
|
const filteredMemories = coreResult.similar_memories.filter(
|
|
125
|
-
(m: any) => m.content_type !== 'ghost'
|
|
125
|
+
(m: any) => m.content_type !== 'ghost' && m.content_type !== 'agent'
|
|
126
126
|
);
|
|
127
127
|
|
|
128
128
|
const result: FindSimilarResult = {
|