Skip to content

Commit 9e99c8f

Browse files
authored
Add URI to autorecall memories (volcengine#2321)
1 parent 1f0b259 commit 9e99c8f

3 files changed

Lines changed: 60 additions & 3 deletions

File tree

examples/openclaw-plugin/auto-recall.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,37 @@ export function estimateTokenCount(text: string): number {
5959

6060
export type BuildMemoryLinesOptions = {
6161
recallPreferAbstract: boolean;
62+
includeUri?: boolean;
6263
};
6364

65+
function memoryCategory(item: FindResultItem): string {
66+
return item.category?.trim() || "memory";
67+
}
68+
69+
function indentContent(content: string): string {
70+
return content
71+
.split("\n")
72+
.map((line) => ` ${line}`)
73+
.join("\n");
74+
}
75+
76+
function formatMemoryLine(
77+
item: FindResultItem,
78+
content: string,
79+
options: BuildMemoryLinesOptions,
80+
): string {
81+
const category = memoryCategory(item);
82+
if (!options.includeUri) {
83+
return `- [${category}] ${content}`;
84+
}
85+
86+
return [
87+
`- [${category}]`,
88+
` <uri>${item.uri}</uri>`,
89+
indentContent(content),
90+
].join("\n");
91+
}
92+
6493
async function resolveMemoryContent(
6594
item: FindResultItem,
6695
readFn: (uri: string) => Promise<string>,
@@ -95,7 +124,7 @@ export async function buildMemoryLines(
95124
const lines: string[] = [];
96125
for (const item of memories) {
97126
const content = await resolveMemoryContent(item, readFn, options);
98-
lines.push(`- [${item.category ?? "memory"}] ${content}`);
127+
lines.push(formatMemoryLine(item, content, options));
99128
}
100129
return lines;
101130
}
@@ -128,7 +157,7 @@ export async function buildMemoryLinesWithBudget(
128157
}
129158

130159
const content = await resolveMemoryContent(item, readFn, options);
131-
const line = `- [${item.category ?? "memory"}] ${content}`;
160+
const line = formatMemoryLine(item, content, options);
132161
const separatorChars = lines.length > 0 ? 1 : 0;
133162
const projectedChars = totalChars + separatorChars + line.length;
134163

@@ -231,6 +260,7 @@ export async function buildAutoRecallContext(params: {
231260
{
232261
recallPreferAbstract: cfg.recallPreferAbstract,
233262
recallMaxInjectedChars: cfg.recallMaxInjectedChars,
263+
includeUri: true,
234264
},
235265
);
236266

examples/openclaw-plugin/tests/ut/build-memory-lines.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,30 @@ describe("buildMemoryLines", () => {
5252
expect(lines[1]).toBe("- [facts] Works at TechCorp");
5353
});
5454

55+
it("includes uri metadata when requested", async () => {
56+
const memories = [
57+
makeMemory({
58+
uri: "viking://user/default/memories/projects/openclaw/autorecall_filename_contract.md",
59+
category: "",
60+
abstract: "Filename carries semantic meaning.",
61+
}),
62+
];
63+
const readFn = vi.fn();
64+
65+
const lines = await buildMemoryLines(memories, readFn, {
66+
recallPreferAbstract: true,
67+
includeUri: true,
68+
});
69+
70+
expect(lines).toEqual([
71+
[
72+
"- [memory]",
73+
" <uri>viking://user/default/memories/projects/openclaw/autorecall_filename_contract.md</uri>",
74+
" Filename carries semantic meaning.",
75+
].join("\n"),
76+
]);
77+
});
78+
5579
it("uses abstract when recallPreferAbstract=true", async () => {
5680
const memories = [makeMemory({ abstract: "The abstract text" })];
5781
const readFn = vi.fn();
@@ -121,7 +145,7 @@ describe("buildMemoryLines", () => {
121145
});
122146

123147
it("defaults category to 'memory'", async () => {
124-
const memories = [makeMemory({ category: undefined })];
148+
const memories = [makeMemory({ category: "" })];
125149
const readFn = vi.fn();
126150

127151
const lines = await buildMemoryLines(memories, readFn, {

examples/openclaw-plugin/tests/ut/context-engine-assemble.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ describe("context-engine assemble()", () => {
147147
expect(result.messages[2]?.role).toBe("user");
148148
expect(result.messages[2]?.content).toMatch(/^<relevant-memories>/);
149149
expect(result.messages[2]?.content).toContain("Source: openviking-auto-recall");
150+
expect(result.messages[2]?.content).toContain(
151+
"<uri>viking://user/default/memories/rust-pref</uri>",
152+
);
150153
expect(result.messages[2]?.content).toContain("User prefers Rust for backend tasks.");
151154
expect(result.messages[2]?.content).toContain("what backend language should we use?");
152155
expect(result.systemPromptAddition).toBeUndefined();

0 commit comments

Comments
 (0)