@echomem/mcp 1.4.6 → 1.4.7
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/assets/hud/session-viewer.html +1699 -0
- package/dist/city/10-problems-report.html +649 -0
- package/dist/city/echo-ai-city-only.html +39 -647
- package/dist/city/echo-ai-city-only.template.html +4 -4
- package/dist/forensics-10-problems.js +632 -0
- package/dist/hud/cli.js +0 -0
- package/dist/hud/electron-main.js +48 -4
- package/dist/hud/preload.cjs +9 -0
- package/dist/hud/server.js +93 -0
- package/dist/hud/web.js +82 -7
- package/dist/index.js +247 -14
- package/dist/setup.js +2 -2
- package/dist/v1-contract.js +134 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import { ZodError } from "zod";
|
|
7
|
-
import { canonicalToolNames, deleteMemorySchema, getByContextSchema, keywordsSchema, listToolSpecs, othersSchema, resolveCanonicalToolName, saveConversationSchema, searchMemoriesSchema, timeRangeSchema, } from "./v1-contract.js";
|
|
7
|
+
import { canonicalToolNames, deleteMemorySchema, getByContextSchema, keywordsSchema, listFriendsSchema, listToolSpecs, othersSchema, publicMemorySchema, resolveCanonicalToolName, saveConversationSchema, searchMemoriesSchema, searchUsersSchema, sendFriendRequestSchema, timeRangeSchema, } from "./v1-contract.js";
|
|
8
8
|
import { KeyStore } from "./keystore.js";
|
|
9
9
|
import { EventLogger, hashText } from "./events.js";
|
|
10
10
|
import { buildReportText } from "./report.js";
|
|
@@ -15,7 +15,6 @@ import { runCli } from "./setup.js";
|
|
|
15
15
|
import { MCP_PACKAGE_VERSION, MCP_SERVER_INSTRUCTIONS } from "./package-metadata.js";
|
|
16
16
|
import { checkLatestUpdateStatus, formatUpdateNotice, formatUpdateStatusText, startBackgroundUpdateCheck, } from "./update-check.js";
|
|
17
17
|
const ECHO_API_BASE_URL = process.env.ECHO_API_BASE_URL || "https://echo-mem-chrome.vercel.app";
|
|
18
|
-
const MEMORY_FEED_API_URL = process.env.MEMORY_FEED_API_URL || "https://memory-feed.vercel.app";
|
|
19
18
|
/** Thrown when no API token is present yet — the model gets a "run login" nudge, not a hard error. */
|
|
20
19
|
class NoTokenError extends Error {
|
|
21
20
|
}
|
|
@@ -379,6 +378,22 @@ function inputAnalyticsForTool(canonicalName, args) {
|
|
|
379
378
|
keyword_count: Array.isArray(a.keywords) ? a.keywords.length : 0,
|
|
380
379
|
limit: numberArg(a, "limit"),
|
|
381
380
|
};
|
|
381
|
+
case canonicalToolNames.searchUsers: {
|
|
382
|
+
const query = readString(a, "query");
|
|
383
|
+
const queryAnalytics = safeTextAnalytics("query", query);
|
|
384
|
+
return {
|
|
385
|
+
...queryAnalytics,
|
|
386
|
+
query_preview_safe: queryAnalytics.query_preview,
|
|
387
|
+
query_length: query?.length ?? 0,
|
|
388
|
+
limit: numberArg(a, "limit"),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
case canonicalToolNames.sendFriendRequest: {
|
|
392
|
+
const targetUserId = readString(a, "targetUserId");
|
|
393
|
+
return {
|
|
394
|
+
target_user_id_hash: targetUserId ? hashText(targetUserId) : undefined,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
382
397
|
case canonicalToolNames.others: {
|
|
383
398
|
const query = readString(a, "query");
|
|
384
399
|
const queryAnalytics = safeTextAnalytics("query", query);
|
|
@@ -386,6 +401,13 @@ function inputAnalyticsForTool(canonicalName, args) {
|
|
|
386
401
|
...queryAnalytics,
|
|
387
402
|
query_preview_safe: queryAnalytics.query_preview,
|
|
388
403
|
query_length: query?.length ?? 0,
|
|
404
|
+
limit: numberArg(a, "limit"),
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
case canonicalToolNames.publicMemory: {
|
|
408
|
+
const memoryId = readString(a, "memoryId");
|
|
409
|
+
return {
|
|
410
|
+
memory_id_hash: memoryId ? hashText(memoryId) : undefined,
|
|
389
411
|
};
|
|
390
412
|
}
|
|
391
413
|
default:
|
|
@@ -773,21 +795,73 @@ class EchoMemApiClient {
|
|
|
773
795
|
});
|
|
774
796
|
return enc.enabled ? await this.decryptResult(response.data, enc.key) : response.data;
|
|
775
797
|
}
|
|
798
|
+
async listFriends(args) {
|
|
799
|
+
listFriendsSchema.parse(args);
|
|
800
|
+
try {
|
|
801
|
+
const response = await this.axios.get("/api/extension/social/friends");
|
|
802
|
+
return response.data;
|
|
803
|
+
}
|
|
804
|
+
catch (error) {
|
|
805
|
+
throw new Error(`list_friends failed against ${ECHO_API_BASE_URL}: ${describeError(error)}`);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
async searchUsers(args) {
|
|
809
|
+
const parsed = searchUsersSchema.parse(args);
|
|
810
|
+
try {
|
|
811
|
+
const response = await this.axios.post("/api/extension/social/users/search", {
|
|
812
|
+
query: parsed.query,
|
|
813
|
+
limit: parsed.limit,
|
|
814
|
+
});
|
|
815
|
+
return response.data;
|
|
816
|
+
}
|
|
817
|
+
catch (error) {
|
|
818
|
+
throw new Error(`search_users failed against ${ECHO_API_BASE_URL}: ${describeError(error)}`);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
async sendFriendRequest(args) {
|
|
822
|
+
const parsed = sendFriendRequestSchema.parse(args);
|
|
823
|
+
try {
|
|
824
|
+
const response = await this.axios.post("/api/extension/social/friend-requests", {
|
|
825
|
+
receiverUserId: parsed.targetUserId,
|
|
826
|
+
});
|
|
827
|
+
return response.data;
|
|
828
|
+
}
|
|
829
|
+
catch (error) {
|
|
830
|
+
throw new Error(`send_friend_request failed against ${ECHO_API_BASE_URL}: ${describeError(error)}`);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
776
833
|
async searchOthersMemories(args) {
|
|
777
834
|
const parsed = othersSchema.parse(args);
|
|
778
835
|
try {
|
|
779
|
-
const response = await axios.post(
|
|
836
|
+
const response = await this.axios.post("/api/extension/social/public-memories/search", {
|
|
780
837
|
query: parsed.query,
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
838
|
+
limit: parsed.limit,
|
|
839
|
+
target: parsed.target,
|
|
840
|
+
ownerUserId: parsed.ownerUserId,
|
|
841
|
+
ownerName: parsed.ownerName,
|
|
842
|
+
targetFriendIds: parsed.targetFriendIds,
|
|
843
|
+
targetFriendNames: parsed.targetFriendNames,
|
|
844
|
+
recordAccess: parsed.recordAccess,
|
|
845
|
+
kPerUser: parsed.kPerUser,
|
|
846
|
+
similarityThreshold: parsed.similarityThreshold,
|
|
847
|
+
timeFrameDays: parsed.timeFrameDays,
|
|
848
|
+
requestId: this.sessionId,
|
|
849
|
+
source: "mcp_friend_public_memory_search",
|
|
786
850
|
});
|
|
787
851
|
return response.data;
|
|
788
852
|
}
|
|
789
853
|
catch (error) {
|
|
790
|
-
throw new Error(`search_others_memories failed against ${
|
|
854
|
+
throw new Error(`search_others_memories failed against ${ECHO_API_BASE_URL}: ${describeError(error)}`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
async getPublicMemory(args) {
|
|
858
|
+
const parsed = publicMemorySchema.parse(args);
|
|
859
|
+
try {
|
|
860
|
+
const response = await this.axios.get(`/api/extension/social/public-memories/${encodeURIComponent(parsed.memoryId)}?requestId=${encodeURIComponent(this.sessionId)}&source=mcp_friend_public_memory_fetch`);
|
|
861
|
+
return response.data;
|
|
862
|
+
}
|
|
863
|
+
catch (error) {
|
|
864
|
+
throw new Error(`get_public_memory failed against ${ECHO_API_BASE_URL}: ${describeError(error)}`);
|
|
791
865
|
}
|
|
792
866
|
}
|
|
793
867
|
}
|
|
@@ -954,8 +1028,16 @@ class EchoMemMCPServer {
|
|
|
954
1028
|
return await this.handleGetByContext(request.params.arguments);
|
|
955
1029
|
case canonicalToolNames.keywords:
|
|
956
1030
|
return await this.handleKeywords(request.params.arguments);
|
|
1031
|
+
case canonicalToolNames.friends:
|
|
1032
|
+
return await this.handleFriends(request.params.arguments);
|
|
1033
|
+
case canonicalToolNames.searchUsers:
|
|
1034
|
+
return await this.handleSearchUsers(request.params.arguments);
|
|
1035
|
+
case canonicalToolNames.sendFriendRequest:
|
|
1036
|
+
return await this.handleSendFriendRequest(request.params.arguments);
|
|
957
1037
|
case canonicalToolNames.others:
|
|
958
1038
|
return await this.handleOthers(request.params.arguments);
|
|
1039
|
+
case canonicalToolNames.publicMemory:
|
|
1040
|
+
return await this.handlePublicMemory(request.params.arguments);
|
|
959
1041
|
case canonicalToolNames.delete:
|
|
960
1042
|
return await this.handleDelete(request.params.arguments, rec);
|
|
961
1043
|
default:
|
|
@@ -1251,26 +1333,177 @@ Details: ${m.details || "N/A"}`)
|
|
|
1251
1333
|
const payload = await this.client.searchOthersMemories(args);
|
|
1252
1334
|
const memories = payload?.memories ?? [];
|
|
1253
1335
|
if (!memories.length) {
|
|
1336
|
+
const scope = parsed.ownerUserId
|
|
1337
|
+
? ` for friend ${parsed.ownerUserId}`
|
|
1338
|
+
: parsed.ownerName
|
|
1339
|
+
? ` for friend ${parsed.ownerName}`
|
|
1340
|
+
: parsed.target
|
|
1341
|
+
? ` for friend ${parsed.target}`
|
|
1342
|
+
: parsed.targetFriendIds?.length
|
|
1343
|
+
? ` for ${parsed.targetFriendIds.length} selected friends`
|
|
1344
|
+
: parsed.targetFriendNames?.length
|
|
1345
|
+
? ` for ${parsed.targetFriendNames.length} named friends`
|
|
1346
|
+
: "";
|
|
1347
|
+
const queryLabel = parsed.query?.trim() ? ` matching the query: ${parsed.query}` : "";
|
|
1254
1348
|
return {
|
|
1255
|
-
content: [{ type: "text", text: `No others' memories found
|
|
1349
|
+
content: [{ type: "text", text: `No others' public memories found${scope}${queryLabel}` }],
|
|
1256
1350
|
};
|
|
1257
1351
|
}
|
|
1352
|
+
const metadata = [
|
|
1353
|
+
typeof payload?.friendCount === "number" ? `friendCount=${payload.friendCount}` : "",
|
|
1354
|
+
typeof payload?.searchedFriendCount === "number" ? `searchedFriendCount=${payload.searchedFriendCount}` : "",
|
|
1355
|
+
typeof payload?.memoryViewsInserted === "number" ? `memoryViewsInserted=${payload.memoryViewsInserted}` : "",
|
|
1356
|
+
].filter(Boolean).join(", ");
|
|
1258
1357
|
const formattedResults = memories
|
|
1259
|
-
.map((m, idx) =>
|
|
1358
|
+
.map((m, idx) => {
|
|
1359
|
+
const score = typeof m.final_score === "number"
|
|
1360
|
+
? m.final_score
|
|
1361
|
+
: typeof m.similarity_score === "number"
|
|
1362
|
+
? m.similarity_score
|
|
1363
|
+
: undefined;
|
|
1364
|
+
return `[${idx + 1}] Memory ID: ${m.id || "unknown"}
|
|
1365
|
+
User ID: ${m.user_id || "unknown"}
|
|
1366
|
+
User Name: ${m.username || m.user_name || m.name || "Anonymous"}
|
|
1260
1367
|
Time: ${m.time} | Location: ${m.location}
|
|
1261
1368
|
Category: ${m.category} | Object: ${m.object}
|
|
1262
|
-
Description: ${m.description}
|
|
1263
|
-
Details: ${m.details || "N/A"}
|
|
1369
|
+
${typeof score === "number" ? `Score: ${score}\n` : ""}Description: ${m.description}
|
|
1370
|
+
Details: ${m.details || "N/A"}`;
|
|
1371
|
+
})
|
|
1264
1372
|
.join("\n\n");
|
|
1265
1373
|
return {
|
|
1266
1374
|
content: [
|
|
1267
1375
|
{
|
|
1268
1376
|
type: "text",
|
|
1269
|
-
text: `Found ${memories.length} others' memories:\n\n${formattedResults}`,
|
|
1377
|
+
text: `Found ${memories.length} others' public memories${metadata ? ` (${metadata})` : ""}:\n\n${formattedResults}`,
|
|
1270
1378
|
},
|
|
1271
1379
|
],
|
|
1272
1380
|
};
|
|
1273
1381
|
}
|
|
1382
|
+
async handleFriends(args) {
|
|
1383
|
+
listFriendsSchema.parse(args);
|
|
1384
|
+
const payload = await this.client.listFriends(args);
|
|
1385
|
+
const friends = Array.isArray(payload?.friends) ? payload.friends : [];
|
|
1386
|
+
if (!friends.length) {
|
|
1387
|
+
return {
|
|
1388
|
+
content: [{ type: "text", text: "No accepted EchoMem friends found." }],
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
const formatted = friends
|
|
1392
|
+
.map((friend, idx) => {
|
|
1393
|
+
const name = typeof friend.name === "string" && friend.name.trim()
|
|
1394
|
+
? friend.name.trim()
|
|
1395
|
+
: "Unnamed friend";
|
|
1396
|
+
const userId = typeof friend.user_id === "string" ? friend.user_id : "unknown";
|
|
1397
|
+
const publicMemoryCount = typeof friend.publicMemoryCount === "number"
|
|
1398
|
+
? friend.publicMemoryCount
|
|
1399
|
+
: 0;
|
|
1400
|
+
return `[${idx + 1}] ${name}\nUser ID: ${userId}\nPublic memories: ${publicMemoryCount}`;
|
|
1401
|
+
})
|
|
1402
|
+
.join("\n\n");
|
|
1403
|
+
const total = typeof payload?.totalPublicMemoryCount === "number"
|
|
1404
|
+
? payload.totalPublicMemoryCount
|
|
1405
|
+
: friends.reduce((sum, friend) => sum + (typeof friend.publicMemoryCount === "number" ? friend.publicMemoryCount : 0), 0);
|
|
1406
|
+
return {
|
|
1407
|
+
content: [{
|
|
1408
|
+
type: "text",
|
|
1409
|
+
text: `Found ${friends.length} accepted friends (totalPublicMemoryCount=${total}):\n\n${formatted}`,
|
|
1410
|
+
}],
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
async handleSearchUsers(args) {
|
|
1414
|
+
const parsed = searchUsersSchema.parse(args);
|
|
1415
|
+
const payload = await this.client.searchUsers(args);
|
|
1416
|
+
const users = Array.isArray(payload?.users) ? payload.users : [];
|
|
1417
|
+
if (!users.length) {
|
|
1418
|
+
return {
|
|
1419
|
+
content: [{ type: "text", text: `No EchoMem users found matching "${parsed.query}".` }],
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
const formatted = users
|
|
1423
|
+
.map((user, idx) => {
|
|
1424
|
+
const displayName = typeof user.displayName === "string" && user.displayName.trim()
|
|
1425
|
+
? user.displayName.trim()
|
|
1426
|
+
: typeof user.username === "string" && user.username.trim()
|
|
1427
|
+
? user.username.trim()
|
|
1428
|
+
: "Unnamed user";
|
|
1429
|
+
const userId = typeof user.userId === "string" ? user.userId : "unknown";
|
|
1430
|
+
const totalMemoryCount = typeof user.totalMemoryCount === "number" ? user.totalMemoryCount : 0;
|
|
1431
|
+
const publicMemoryCount = typeof user.publicMemoryCount === "number" ? user.publicMemoryCount : 0;
|
|
1432
|
+
const relationship = typeof user.relationshipStatus === "string" ? user.relationshipStatus : "none";
|
|
1433
|
+
const pendingRequestId = typeof user.pendingRequestId === "string" && user.pendingRequestId
|
|
1434
|
+
? `\nPending request ID: ${user.pendingRequestId}`
|
|
1435
|
+
: "";
|
|
1436
|
+
return `[${idx + 1}] ${displayName}\nUser ID: ${userId}\nTotal memories: ${totalMemoryCount}\nPublic memories: ${publicMemoryCount}\nRelationship: ${relationship}${pendingRequestId}`;
|
|
1437
|
+
})
|
|
1438
|
+
.join("\n\n");
|
|
1439
|
+
return {
|
|
1440
|
+
content: [{
|
|
1441
|
+
type: "text",
|
|
1442
|
+
text: `Found ${users.length} EchoMem users matching "${parsed.query}":\n\n${formatted}\n\nUse send_friend_request with the exact User ID to send a pending friend request.`,
|
|
1443
|
+
}],
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
async handleSendFriendRequest(args) {
|
|
1447
|
+
sendFriendRequestSchema.parse(args);
|
|
1448
|
+
const payload = await this.client.sendFriendRequest(args);
|
|
1449
|
+
const result = isRecord(payload) ? payload : {};
|
|
1450
|
+
const targetUser = isRecord(result.targetUser) ? result.targetUser : {};
|
|
1451
|
+
const confirmation = isRecord(result.confirmation) ? result.confirmation : {};
|
|
1452
|
+
const request = isRecord(result.request) ? result.request : {};
|
|
1453
|
+
const created = result.created === true;
|
|
1454
|
+
const displayName = readString(targetUser, "displayName") ?? readString(targetUser, "username") ?? "Unnamed user";
|
|
1455
|
+
const userId = readString(targetUser, "userId") ?? "unknown";
|
|
1456
|
+
const relationship = readString(targetUser, "relationshipStatus") ?? "pending_sent";
|
|
1457
|
+
const requestId = readString(request, "id") ?? readString(targetUser, "pendingRequestId") ?? "unknown";
|
|
1458
|
+
const status = readString(confirmation, "status") ?? "pending";
|
|
1459
|
+
const requiresApproval = confirmation.requiresApproval === true;
|
|
1460
|
+
const message = readString(confirmation, "message") ?? "Friend request is pending approval.";
|
|
1461
|
+
return {
|
|
1462
|
+
content: [{
|
|
1463
|
+
type: "text",
|
|
1464
|
+
text: [
|
|
1465
|
+
created ? "Friend request sent." : "Friend request was not duplicated.",
|
|
1466
|
+
"",
|
|
1467
|
+
`Target: ${displayName}`,
|
|
1468
|
+
`Target User ID: ${userId}`,
|
|
1469
|
+
`Relationship: ${relationship}`,
|
|
1470
|
+
`Request ID: ${requestId}`,
|
|
1471
|
+
`Status: ${status}`,
|
|
1472
|
+
`Requires approval: ${requiresApproval ? "yes" : "no"}`,
|
|
1473
|
+
"",
|
|
1474
|
+
`Confirmation: ${message}`,
|
|
1475
|
+
].join("\n"),
|
|
1476
|
+
}],
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
async handlePublicMemory(args) {
|
|
1480
|
+
const parsed = publicMemorySchema.parse(args);
|
|
1481
|
+
const payload = await this.client.getPublicMemory(args);
|
|
1482
|
+
const memory = payload?.memory;
|
|
1483
|
+
if (!memory) {
|
|
1484
|
+
return {
|
|
1485
|
+
content: [{ type: "text", text: `Public memory ${parsed.memoryId} was not found or is not accessible.` }],
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
const text = [
|
|
1489
|
+
`Memory ID: ${memory.id || parsed.memoryId}`,
|
|
1490
|
+
`Owner User ID: ${memory.owner_user_id || memory.user_id || "Unknown"}`,
|
|
1491
|
+
memory.time ? `Time: ${memory.time}` : "",
|
|
1492
|
+
memory.location ? `Location: ${memory.location}` : "",
|
|
1493
|
+
memory.category ? `Category: ${memory.category}` : "",
|
|
1494
|
+
memory.object ? `Object: ${memory.object}` : "",
|
|
1495
|
+
memory.emotion ? `Emotion: ${memory.emotion}` : "",
|
|
1496
|
+
memory.keys ? `Keys: ${memory.keys}` : "",
|
|
1497
|
+
`Description: ${memory.description || ""}`,
|
|
1498
|
+
memory.details ? `Details: ${memory.details}` : "",
|
|
1499
|
+
typeof payload.accessRecordsInserted === "number"
|
|
1500
|
+
? `Access records inserted: ${payload.accessRecordsInserted}`
|
|
1501
|
+
: "",
|
|
1502
|
+
].filter(Boolean).join("\n");
|
|
1503
|
+
return {
|
|
1504
|
+
content: [{ type: "text", text }],
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1274
1507
|
async handleDelete(args, rec) {
|
|
1275
1508
|
const parsed = deleteMemorySchema.parse(args);
|
|
1276
1509
|
if (rec) {
|
package/dist/setup.js
CHANGED
|
@@ -275,8 +275,8 @@ export function resolveServerEntryVersion(entry) {
|
|
|
275
275
|
}
|
|
276
276
|
const candidates = [...args, command].filter((value) => typeof value === "string");
|
|
277
277
|
for (const candidate of candidates) {
|
|
278
|
-
|
|
279
|
-
|
|
278
|
+
if (!candidate.includes(MCP_PACKAGE_NAME) && !candidate.includes(`${path.sep}echomem-mcp`))
|
|
279
|
+
continue;
|
|
280
280
|
const resolved = packageVersionFromPath(candidate);
|
|
281
281
|
if (resolved)
|
|
282
282
|
return resolved;
|
package/dist/v1-contract.js
CHANGED
|
@@ -5,7 +5,11 @@ export const canonicalToolNames = {
|
|
|
5
5
|
save: "save_conversation",
|
|
6
6
|
timeRange: "get_memories_by_time_range",
|
|
7
7
|
keywords: "search_memories_by_keywords",
|
|
8
|
+
friends: "list_friends",
|
|
9
|
+
searchUsers: "search_users",
|
|
10
|
+
sendFriendRequest: "send_friend_request",
|
|
8
11
|
others: "search_others_memories",
|
|
12
|
+
publicMemory: "get_public_memory",
|
|
9
13
|
report: "echomem_usage_report",
|
|
10
14
|
updateStatus: "echomem_update_status",
|
|
11
15
|
contextHealth: "echo_context_health",
|
|
@@ -59,9 +63,35 @@ export const keywordsSchema = z.object({
|
|
|
59
63
|
keywords: z.array(z.string()),
|
|
60
64
|
limit: z.number().optional().default(10),
|
|
61
65
|
});
|
|
66
|
+
export const listFriendsSchema = z.object({
|
|
67
|
+
...triggerMetadataSchema,
|
|
68
|
+
});
|
|
69
|
+
export const searchUsersSchema = z.object({
|
|
70
|
+
...triggerMetadataSchema,
|
|
71
|
+
query: z.string().min(1),
|
|
72
|
+
limit: z.number().optional().default(10),
|
|
73
|
+
});
|
|
74
|
+
export const sendFriendRequestSchema = z.object({
|
|
75
|
+
...triggerMetadataSchema,
|
|
76
|
+
targetUserId: z.string().min(1),
|
|
77
|
+
});
|
|
62
78
|
export const othersSchema = z.object({
|
|
63
79
|
...triggerMetadataSchema,
|
|
64
|
-
query: z.string(),
|
|
80
|
+
query: z.string().optional().default(""),
|
|
81
|
+
limit: z.number().optional().default(10),
|
|
82
|
+
target: z.string().optional(),
|
|
83
|
+
ownerUserId: z.string().optional(),
|
|
84
|
+
ownerName: z.string().optional(),
|
|
85
|
+
targetFriendIds: z.array(z.string()).optional(),
|
|
86
|
+
targetFriendNames: z.array(z.string()).optional(),
|
|
87
|
+
recordAccess: z.boolean().optional(),
|
|
88
|
+
kPerUser: z.number().optional(),
|
|
89
|
+
similarityThreshold: z.number().optional(),
|
|
90
|
+
timeFrameDays: z.number().optional(),
|
|
91
|
+
});
|
|
92
|
+
export const publicMemorySchema = z.object({
|
|
93
|
+
...triggerMetadataSchema,
|
|
94
|
+
memoryId: z.string().min(1),
|
|
65
95
|
});
|
|
66
96
|
export const deleteMemorySchema = z.object({
|
|
67
97
|
memoryId: z.string().min(1),
|
|
@@ -196,20 +226,121 @@ export function listToolSpecs(opts = {}) {
|
|
|
196
226
|
required: ["keywords"],
|
|
197
227
|
},
|
|
198
228
|
},
|
|
229
|
+
{
|
|
230
|
+
name: canonicalToolNames.friends,
|
|
231
|
+
description: "Friends: list accepted EchoMem friends with each friend's public memory count. Use this before asking a specific friend by name.",
|
|
232
|
+
inputSchema: {
|
|
233
|
+
type: "object",
|
|
234
|
+
properties: {
|
|
235
|
+
triggerMessage: {
|
|
236
|
+
type: "string",
|
|
237
|
+
description: "Optional: the user's message that caused this friend-list lookup. EchoMem stores only a redacted analytics preview and hash.",
|
|
238
|
+
},
|
|
239
|
+
triggerMessageRole: { type: "string", default: "user" },
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: canonicalToolNames.searchUsers,
|
|
245
|
+
description: "Search EchoMem users by display name/username before sending a friend request. Results include total memories, public memories, and current relationship state.",
|
|
246
|
+
inputSchema: {
|
|
247
|
+
type: "object",
|
|
248
|
+
properties: {
|
|
249
|
+
query: {
|
|
250
|
+
type: "string",
|
|
251
|
+
description: "Name or username fragment to search, e.g. Kobe.",
|
|
252
|
+
},
|
|
253
|
+
limit: { type: "number", default: 10 },
|
|
254
|
+
triggerMessage: {
|
|
255
|
+
type: "string",
|
|
256
|
+
description: "Optional: the user's message that caused this user search. EchoMem stores only a redacted analytics preview and hash.",
|
|
257
|
+
},
|
|
258
|
+
triggerMessageRole: { type: "string", default: "user" },
|
|
259
|
+
},
|
|
260
|
+
required: ["query"],
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: canonicalToolNames.sendFriendRequest,
|
|
265
|
+
description: "Send a pending EchoMem friend request to an exact user id returned by search_users. The other user must approve before friend-gated memory access is allowed.",
|
|
266
|
+
inputSchema: {
|
|
267
|
+
type: "object",
|
|
268
|
+
properties: {
|
|
269
|
+
targetUserId: {
|
|
270
|
+
type: "string",
|
|
271
|
+
description: "Exact target user id from search_users.",
|
|
272
|
+
},
|
|
273
|
+
triggerMessage: {
|
|
274
|
+
type: "string",
|
|
275
|
+
description: "Optional: the user's message that caused this friend request. EchoMem stores only a redacted analytics preview and hash.",
|
|
276
|
+
},
|
|
277
|
+
triggerMessageRole: { type: "string", default: "user" },
|
|
278
|
+
},
|
|
279
|
+
required: ["targetUserId"],
|
|
280
|
+
},
|
|
281
|
+
},
|
|
199
282
|
{
|
|
200
283
|
name: canonicalToolNames.others,
|
|
201
|
-
description: "Search
|
|
284
|
+
description: "Search accepted friends' public memories. Returned memories are recorded in the existing memory_views pipeline for the memory owners.",
|
|
202
285
|
inputSchema: {
|
|
203
286
|
type: "object",
|
|
204
287
|
properties: {
|
|
205
288
|
query: { type: "string" },
|
|
289
|
+
limit: { type: "number", default: 10 },
|
|
290
|
+
target: {
|
|
291
|
+
type: "string",
|
|
292
|
+
description: "Accepted-friend user id or exact display name/username. Prefer this for @Name asks.",
|
|
293
|
+
},
|
|
294
|
+
ownerUserId: {
|
|
295
|
+
type: "string",
|
|
296
|
+
description: "Optional accepted-friend user id to scope the search to one friend.",
|
|
297
|
+
},
|
|
298
|
+
ownerName: {
|
|
299
|
+
type: "string",
|
|
300
|
+
description: "Optional accepted-friend display name/username to scope the search to one friend.",
|
|
301
|
+
},
|
|
302
|
+
targetFriendIds: {
|
|
303
|
+
type: "array",
|
|
304
|
+
items: { type: "string" },
|
|
305
|
+
description: "Optional accepted-friend user ids to scope the search.",
|
|
306
|
+
},
|
|
307
|
+
targetFriendNames: {
|
|
308
|
+
type: "array",
|
|
309
|
+
items: { type: "string" },
|
|
310
|
+
description: "Optional accepted-friend display names/usernames to scope the search.",
|
|
311
|
+
},
|
|
312
|
+
recordAccess: {
|
|
313
|
+
type: "boolean",
|
|
314
|
+
description: "Defaults true. When true, returned public memories are recorded in memory_views.",
|
|
315
|
+
},
|
|
316
|
+
kPerUser: { type: "number", default: 5 },
|
|
317
|
+
similarityThreshold: { type: "number", default: 0.1 },
|
|
318
|
+
timeFrameDays: { type: "number" },
|
|
206
319
|
triggerMessage: {
|
|
207
320
|
type: "string",
|
|
208
321
|
description: "Optional: the user's message that caused this public-memory search. EchoMem stores only a redacted analytics preview and hash.",
|
|
209
322
|
},
|
|
210
323
|
triggerMessageRole: { type: "string", default: "user" },
|
|
211
324
|
},
|
|
212
|
-
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: canonicalToolNames.publicMemory,
|
|
329
|
+
description: "Fetch one accepted friend's public memory by id. If the caller is not the owner, EchoMem records the access in the existing memory_views pipeline.",
|
|
330
|
+
inputSchema: {
|
|
331
|
+
type: "object",
|
|
332
|
+
properties: {
|
|
333
|
+
memoryId: {
|
|
334
|
+
type: "string",
|
|
335
|
+
description: "The public memory id to fetch.",
|
|
336
|
+
},
|
|
337
|
+
triggerMessage: {
|
|
338
|
+
type: "string",
|
|
339
|
+
description: "Optional: the user's message that caused this public-memory fetch. EchoMem stores only a redacted analytics preview and hash.",
|
|
340
|
+
},
|
|
341
|
+
triggerMessageRole: { type: "string", default: "user" },
|
|
342
|
+
},
|
|
343
|
+
required: ["memoryId"],
|
|
213
344
|
},
|
|
214
345
|
},
|
|
215
346
|
{
|