mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-08-28 05:25:04 +00:00
fix: preserve original OpenClaw prompts
This commit is contained in:
parent
4c3bdec430
commit
18f914454b
4 changed files with 82 additions and 11 deletions
|
|
@ -20,9 +20,11 @@ const plugin: OpenClawPluginDefinition = {
|
|||
const runtime = new OpenClawReMeRuntime(client, config, api.logger);
|
||||
registerOpenClawTools(api, client, config);
|
||||
|
||||
if (config.autoRecall) {
|
||||
if (config.autoRecall || config.autoCapture) {
|
||||
api.on("before_agent_start", async (event, context) => {
|
||||
if (!capturesTrigger(context.trigger)) return;
|
||||
runtime.rememberPrompt(event.prompt, context);
|
||||
if (!config.autoRecall) return;
|
||||
const query = event.prompt.trim();
|
||||
if (!query) return;
|
||||
const result = await client.search(query, {
|
||||
|
|
@ -41,7 +43,8 @@ const plugin: OpenClawPluginDefinition = {
|
|||
}
|
||||
|
||||
api.on("agent_end", (event, context) => {
|
||||
if (event.success) runtime.capture(event.messages, context);
|
||||
const prompt = runtime.takePrompt(context);
|
||||
if (event.success) runtime.capture(event.messages, context, prompt);
|
||||
});
|
||||
|
||||
api.registerService({
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export function openClawSessionId(value: string): string {
|
|||
export function captureLastTurn(
|
||||
messages: unknown[],
|
||||
sessionId: string,
|
||||
userPrompt?: string,
|
||||
): ReMeMessage[] {
|
||||
let assistant: ReMeMessage | null = null;
|
||||
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
||||
|
|
@ -29,7 +30,13 @@ export function captureLastTurn(
|
|||
continue;
|
||||
}
|
||||
if (assistant && record.role === "user") {
|
||||
const user = normalizeMessage(record, "user", sessionId, index);
|
||||
const user = normalizeMessage(
|
||||
record,
|
||||
"user",
|
||||
sessionId,
|
||||
index,
|
||||
userPrompt,
|
||||
);
|
||||
return user ? [user, assistant] : [];
|
||||
}
|
||||
}
|
||||
|
|
@ -41,8 +48,10 @@ function normalizeMessage(
|
|||
role: "user" | "assistant",
|
||||
sessionId: string,
|
||||
index: number,
|
||||
textOverride?: string,
|
||||
): ReMeMessage | null {
|
||||
const text = stripAutoRecallContext(messageText(value.content));
|
||||
const text =
|
||||
textOverride?.trim() || stripAutoRecallContext(messageText(value.content));
|
||||
if (!text) return null;
|
||||
const nativeId =
|
||||
typeof value.id === "string" && value.id ? value.id : `${index}\n${text}`;
|
||||
|
|
@ -58,11 +67,12 @@ function normalizeMessage(
|
|||
|
||||
function stripAutoRecallContext(value: string): string {
|
||||
const opening = '<reme-context source="auto-recall">';
|
||||
if (!value.startsWith(opening)) return value;
|
||||
const start = value.indexOf(opening);
|
||||
if (start === -1) return value;
|
||||
const closing = "</reme-context>";
|
||||
const end = value.indexOf(closing, opening.length);
|
||||
const end = value.indexOf(closing, start + opening.length);
|
||||
if (end === -1) return value;
|
||||
return value.slice(end + closing.length).trim();
|
||||
return `${value.slice(0, start)}${value.slice(end + closing.length)}`.trim();
|
||||
}
|
||||
|
||||
function messageText(content: unknown): string {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export interface OpenClawAgentContext {
|
|||
export class OpenClawReMeRuntime {
|
||||
private writes = Promise.resolve();
|
||||
private controller = new AbortController();
|
||||
private readonly prompts = new Map<string, string>();
|
||||
|
||||
constructor(
|
||||
readonly client: ReMeClientLike,
|
||||
|
|
@ -21,7 +22,26 @@ export class OpenClawReMeRuntime {
|
|||
readonly logger: LoggerLike,
|
||||
) {}
|
||||
|
||||
capture(messages: unknown[], context: OpenClawAgentContext): void {
|
||||
rememberPrompt(prompt: string, context: OpenClawAgentContext): void {
|
||||
if (!this.config.autoCapture || !capturesTrigger(context.trigger)) return;
|
||||
const key = promptKey(context);
|
||||
const text = prompt.trim();
|
||||
if (key && text) this.prompts.set(key, text);
|
||||
}
|
||||
|
||||
takePrompt(context: OpenClawAgentContext): string | undefined {
|
||||
const key = promptKey(context);
|
||||
if (!key) return undefined;
|
||||
const prompt = this.prompts.get(key);
|
||||
this.prompts.delete(key);
|
||||
return prompt;
|
||||
}
|
||||
|
||||
capture(
|
||||
messages: unknown[],
|
||||
context: OpenClawAgentContext,
|
||||
prompt?: string,
|
||||
): void {
|
||||
if (!this.config.autoCapture || !capturesTrigger(context.trigger)) return;
|
||||
const nativeSessionId = context.sessionId || context.sessionKey;
|
||||
if (!nativeSessionId) {
|
||||
|
|
@ -33,7 +53,7 @@ export class OpenClawReMeRuntime {
|
|||
const sessionId = openClawSessionId(
|
||||
`${context.agentId || "default"}\n${nativeSessionId}`,
|
||||
);
|
||||
const captured = captureLastTurn(messages, sessionId);
|
||||
const captured = captureLastTurn(messages, sessionId, prompt);
|
||||
if (captured.length !== 2) return;
|
||||
this.writes = this.writes
|
||||
.then(async () => {
|
||||
|
|
@ -71,3 +91,10 @@ export class OpenClawReMeRuntime {
|
|||
function capturesTrigger(trigger: string | undefined): boolean {
|
||||
return trigger === undefined || trigger === "user";
|
||||
}
|
||||
|
||||
function promptKey(context: OpenClawAgentContext): string {
|
||||
const nativeSessionId = context.sessionId || context.sessionKey;
|
||||
return nativeSessionId
|
||||
? `${context.agentId || "default"}\n${nativeSessionId}`
|
||||
: "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,30 @@ test("removes recalled context while preserving the current OpenClaw prompt", ()
|
|||
);
|
||||
});
|
||||
|
||||
test("uses the original prompt when other plugins prepend context around recall", () => {
|
||||
const messages = captureLastTurn(
|
||||
[
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"other plugin context\n\n" +
|
||||
'<reme-context source="auto-recall">\nremembered deployment\n</reme-context>\n\n' +
|
||||
"another plugin context\n\nremember blue",
|
||||
},
|
||||
{ role: "assistant", content: "noted" },
|
||||
],
|
||||
"session",
|
||||
"remember blue",
|
||||
);
|
||||
assert.deepEqual(
|
||||
messages.map((message) => [message.role, message.content[0].text]),
|
||||
[
|
||||
["user", "remember blue"],
|
||||
["assistant", "noted"],
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test("registers OpenClaw recall, capture, tool, and shutdown lifecycle", async () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
const calls = [];
|
||||
|
|
@ -114,7 +138,7 @@ test("registers OpenClaw recall, capture, tool, and shutdown lifecycle", async (
|
|||
assert.equal(tools[0].name, "reme_search");
|
||||
const recalled = await hooks.get("before_agent_start")(
|
||||
{ prompt: "deployment" },
|
||||
{ trigger: "user" },
|
||||
{ trigger: "user", agentId: "main", sessionId: "session-1" },
|
||||
);
|
||||
assert.match(recalled.prependContext, /remembered deployment/);
|
||||
|
||||
|
|
@ -122,7 +146,13 @@ test("registers OpenClaw recall, capture, tool, and shutdown lifecycle", async (
|
|||
{
|
||||
success: true,
|
||||
messages: [
|
||||
{ role: "user", content: "remember blue" },
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"other plugin context\n\n" +
|
||||
recalled.prependContext +
|
||||
"\n\ndeployment",
|
||||
},
|
||||
{ role: "assistant", content: "noted" },
|
||||
],
|
||||
},
|
||||
|
|
@ -134,6 +164,7 @@ test("registers OpenClaw recall, capture, tool, and shutdown lifecycle", async (
|
|||
calls.map((call) => call.url),
|
||||
["http://127.0.0.1:2333/search", "http://127.0.0.1:2333/auto_memory"],
|
||||
);
|
||||
assert.equal(calls[1].body.messages[0].content[0].text, "deployment");
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue