@mingxy/cerebro 1.4.1 → 1.5.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/package.json +1 -1
- package/src/client.ts +15 -0
- package/src/hooks.ts +73 -2
- package/src/index.ts +2 -2
- package/src/tools.ts +5 -0
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -84,6 +84,7 @@ export interface MemoryDto {
|
|
|
84
84
|
source?: string;
|
|
85
85
|
tenant_id: string;
|
|
86
86
|
agent_id?: string;
|
|
87
|
+
importance: number;
|
|
87
88
|
created_at: string;
|
|
88
89
|
updated_at: string;
|
|
89
90
|
}
|
|
@@ -171,6 +172,7 @@ export class OmemClient {
|
|
|
171
172
|
scope?: string,
|
|
172
173
|
agentId?: string,
|
|
173
174
|
sessionId?: string,
|
|
175
|
+
visibility?: string,
|
|
174
176
|
): Promise<MemoryDto | null> {
|
|
175
177
|
const safeContent = sanitizeContent(content, this.getCfg("maxContentChars", 30000));
|
|
176
178
|
return this.post<MemoryDto>("/v1/memories", {
|
|
@@ -180,6 +182,7 @@ export class OmemClient {
|
|
|
180
182
|
scope,
|
|
181
183
|
agent_id: agentId,
|
|
182
184
|
session_id: sessionId,
|
|
185
|
+
visibility,
|
|
183
186
|
});
|
|
184
187
|
}
|
|
185
188
|
|
|
@@ -356,4 +359,16 @@ export class OmemClient {
|
|
|
356
359
|
);
|
|
357
360
|
return res?.recalls ?? [];
|
|
358
361
|
}
|
|
362
|
+
|
|
363
|
+
async sessionIngest(
|
|
364
|
+
messages: Array<{ role: string; content: string }>,
|
|
365
|
+
sessionId?: string,
|
|
366
|
+
agentId?: string,
|
|
367
|
+
): Promise<unknown> {
|
|
368
|
+
return this.post("/v1/memories/session-ingest", {
|
|
369
|
+
messages,
|
|
370
|
+
session_id: sessionId,
|
|
371
|
+
agent_id: agentId,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
359
374
|
}
|
package/src/hooks.ts
CHANGED
|
@@ -102,13 +102,15 @@ function buildClusteredContextBlock(clustered: import("./client.js").ClusteredRe
|
|
|
102
102
|
if (clustered.cluster_summaries.length > 0) {
|
|
103
103
|
sections.push("## 📋 主题簇(聚合记忆)");
|
|
104
104
|
for (const cs of clustered.cluster_summaries) {
|
|
105
|
-
|
|
105
|
+
const scoreIndicator = cs.relevance_score >= 0.8 ? "★★★" : cs.relevance_score >= 0.6 ? "★★" : "★";
|
|
106
|
+
sections.push(`\n### ${cs.title} (整合自${cs.member_count}条记忆) ${scoreIndicator}`);
|
|
106
107
|
sections.push(`> ${cs.summary}`);
|
|
107
108
|
if (cs.key_memories.length > 0) {
|
|
108
109
|
sections.push("**核心要点:**");
|
|
109
110
|
for (const mem of cs.key_memories) {
|
|
110
111
|
const content = truncate(mem.content, maxContentLength);
|
|
111
|
-
|
|
112
|
+
const importanceBar = mem.importance >= 0.7 ? "●" : mem.importance >= 0.4 ? "◐" : "○";
|
|
113
|
+
sections.push(`- ${importanceBar} ${content}`);
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
116
|
}
|
|
@@ -341,6 +343,75 @@ export function keywordDetectionHook(client: OmemClient, containerTags: string[]
|
|
|
341
343
|
};
|
|
342
344
|
}
|
|
343
345
|
|
|
346
|
+
const processedMessageIds = new Set<string>();
|
|
347
|
+
|
|
348
|
+
export function sessionIdleHook(
|
|
349
|
+
omemClient: OmemClient,
|
|
350
|
+
_containerTags: string[],
|
|
351
|
+
tui: any,
|
|
352
|
+
sdkClient: any,
|
|
353
|
+
_ingestMode: "smart" | "raw" = "smart",
|
|
354
|
+
) {
|
|
355
|
+
let idleTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
356
|
+
let isCapturing = false;
|
|
357
|
+
|
|
358
|
+
return async (input: { event: { type: string; properties?: any } }) => {
|
|
359
|
+
if (input.event.type !== "session.idle") return;
|
|
360
|
+
|
|
361
|
+
const sessionID = input.event.properties?.sessionID;
|
|
362
|
+
if (!sessionID) return;
|
|
363
|
+
|
|
364
|
+
if (idleTimeout) clearTimeout(idleTimeout);
|
|
365
|
+
|
|
366
|
+
idleTimeout = setTimeout(async () => {
|
|
367
|
+
if (isCapturing) return;
|
|
368
|
+
isCapturing = true;
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
const response = await sdkClient.session.messages({ path: { id: sessionID } });
|
|
372
|
+
if (!response?.data) return;
|
|
373
|
+
|
|
374
|
+
const messages = response.data;
|
|
375
|
+
const conversationMessages: Array<{ role: string; content: string }> = [];
|
|
376
|
+
let hasNewMessages = false;
|
|
377
|
+
|
|
378
|
+
for (const msg of messages) {
|
|
379
|
+
const msgId = msg.info?.id;
|
|
380
|
+
if (!msgId || processedMessageIds.has(msgId)) continue;
|
|
381
|
+
|
|
382
|
+
const role = msg.info?.role;
|
|
383
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
384
|
+
|
|
385
|
+
const textParts = (msg.parts || [])
|
|
386
|
+
.filter((p: any) => p.type === "text" && p.text)
|
|
387
|
+
.map((p: any) => p.text);
|
|
388
|
+
const text = textParts.join("\n").trim();
|
|
389
|
+
if (!text) continue;
|
|
390
|
+
|
|
391
|
+
hasNewMessages = true;
|
|
392
|
+
processedMessageIds.add(msgId);
|
|
393
|
+
conversationMessages.push({ role, content: text });
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (!hasNewMessages || conversationMessages.length === 0) return;
|
|
397
|
+
|
|
398
|
+
try {
|
|
399
|
+
await omemClient.sessionIngest(conversationMessages, sessionID);
|
|
400
|
+
showToast(tui, "🧠 Memory Sealed", `${conversationMessages.length} dialogues captured · entrusted to the heavens for refinement`, "success");
|
|
401
|
+
} catch (err) {
|
|
402
|
+
showToast(tui, "🔴 Session Capture Failed", String(err).substring(0, 100), "error");
|
|
403
|
+
}
|
|
404
|
+
} catch (err) {
|
|
405
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
406
|
+
showToast(tui, "🔴 Idle Capture Error", errMsg.substring(0, 100), "error");
|
|
407
|
+
} finally {
|
|
408
|
+
isCapturing = false;
|
|
409
|
+
idleTimeout = null;
|
|
410
|
+
}
|
|
411
|
+
}, 10000);
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
344
415
|
export function compactingHook(client: OmemClient, containerTags: string[], tui: any, ingestMode: "smart" | "raw" = "smart") {
|
|
345
416
|
return async (
|
|
346
417
|
input: { sessionID?: string },
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { join, dirname } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { OmemClient } from "./client.js";
|
|
6
|
-
import { autoRecallHook, compactingHook,
|
|
6
|
+
import { autoRecallHook, compactingHook, sessionIdleHook } from "./hooks.js";
|
|
7
7
|
import { getUserTag, getProjectTag } from "./tags.js";
|
|
8
8
|
import { buildTools } from "./tools.js";
|
|
9
9
|
import { logInfo, logError } from "./logger.js";
|
|
@@ -93,9 +93,9 @@ const OmemPlugin: Plugin = async (input) => {
|
|
|
93
93
|
if (input.sessionID) currentSessionId = input.sessionID;
|
|
94
94
|
return recallHook(input, output);
|
|
95
95
|
},
|
|
96
|
-
"chat.message": keywordDetectionHook(omemClient, containerTags, config.autoCaptureThreshold, tui, config.ingestMode),
|
|
97
96
|
"experimental.session.compacting": compactingHook(omemClient, containerTags, tui, config.ingestMode),
|
|
98
97
|
tool: buildTools(omemClient, containerTags, { agentId, getSessionId: () => currentSessionId }),
|
|
98
|
+
event: sessionIdleHook(omemClient, containerTags, tui, client, config.ingestMode),
|
|
99
99
|
"shell.env": async (_input: any, output: any) => {
|
|
100
100
|
if (directory) {
|
|
101
101
|
output.env.OMEM_PROJECT_DIR = directory;
|
package/src/tools.ts
CHANGED
|
@@ -45,6 +45,10 @@ export function buildTools(client: OmemClient, containerTags: string[], context:
|
|
|
45
45
|
.string()
|
|
46
46
|
.optional()
|
|
47
47
|
.describe("Memory scope: 'project' (default, only visible in this project) or 'global' (visible across all projects)"),
|
|
48
|
+
visibility: tool.schema
|
|
49
|
+
.string()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe("Memory visibility: 'global' (default, visible to all agents) or 'private' (only visible to the storing agent). Use 'private' for sensitive data like credentials, personal info, or anything the user wouldn't want shared."),
|
|
48
52
|
},
|
|
49
53
|
async execute(args) {
|
|
50
54
|
const allTags = [...containerTags, ...(args.tags ?? [])];
|
|
@@ -55,6 +59,7 @@ export function buildTools(client: OmemClient, containerTags: string[], context:
|
|
|
55
59
|
args.scope ?? "project",
|
|
56
60
|
context.agentId,
|
|
57
61
|
context.getSessionId(),
|
|
62
|
+
args.visibility,
|
|
58
63
|
);
|
|
59
64
|
if (!result) return JSON.stringify({ ok: false, error: "The omem server may be unavailable." });
|
|
60
65
|
return JSON.stringify({ ok: true, id: result.id, tags: result.tags });
|