mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 04:41:25 +00:00
feat: add experimental session memory source
This commit is contained in:
@@ -99,4 +99,42 @@ describe("memory search config", () => {
|
||||
headers: { "X-Default": "on" },
|
||||
});
|
||||
});
|
||||
|
||||
it("gates session sources behind experimental flag", () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
memorySearch: {
|
||||
sources: ["memory", "sessions"],
|
||||
},
|
||||
},
|
||||
list: [
|
||||
{
|
||||
id: "main",
|
||||
default: true,
|
||||
memorySearch: {
|
||||
experimental: { sessionMemory: false },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const resolved = resolveMemorySearchConfig(cfg, "main");
|
||||
expect(resolved?.sources).toEqual(["memory"]);
|
||||
});
|
||||
|
||||
it("allows session sources when experimental flag is enabled", () => {
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
memorySearch: {
|
||||
sources: ["memory", "sessions"],
|
||||
experimental: { sessionMemory: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const resolved = resolveMemorySearchConfig(cfg, "main");
|
||||
expect(resolved?.sources).toContain("sessions");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,12 +8,16 @@ import { resolveAgentConfig } from "./agent-scope.js";
|
||||
|
||||
export type ResolvedMemorySearchConfig = {
|
||||
enabled: boolean;
|
||||
sources: Array<"memory" | "sessions">;
|
||||
provider: "openai" | "local";
|
||||
remote?: {
|
||||
baseUrl?: string;
|
||||
apiKey?: string;
|
||||
headers?: Record<string, string>;
|
||||
};
|
||||
experimental: {
|
||||
sessionMemory: boolean;
|
||||
};
|
||||
fallback: "openai" | "none";
|
||||
model: string;
|
||||
local: {
|
||||
@@ -51,6 +55,21 @@ const DEFAULT_CHUNK_OVERLAP = 80;
|
||||
const DEFAULT_WATCH_DEBOUNCE_MS = 1500;
|
||||
const DEFAULT_MAX_RESULTS = 6;
|
||||
const DEFAULT_MIN_SCORE = 0.35;
|
||||
const DEFAULT_SOURCES: Array<"memory" | "sessions"> = ["memory"];
|
||||
|
||||
function normalizeSources(
|
||||
sources: Array<"memory" | "sessions"> | undefined,
|
||||
sessionMemoryEnabled: boolean,
|
||||
): Array<"memory" | "sessions"> {
|
||||
const normalized = new Set<"memory" | "sessions">();
|
||||
const input = sources?.length ? sources : DEFAULT_SOURCES;
|
||||
for (const source of input) {
|
||||
if (source === "memory") normalized.add("memory");
|
||||
if (source === "sessions" && sessionMemoryEnabled) normalized.add("sessions");
|
||||
}
|
||||
if (normalized.size === 0) normalized.add("memory");
|
||||
return Array.from(normalized);
|
||||
}
|
||||
|
||||
function resolveStorePath(agentId: string, raw?: string): string {
|
||||
const stateDir = resolveStateDir(process.env, os.homedir);
|
||||
@@ -66,6 +85,8 @@ function mergeConfig(
|
||||
agentId: string,
|
||||
): ResolvedMemorySearchConfig {
|
||||
const enabled = overrides?.enabled ?? defaults?.enabled ?? true;
|
||||
const sessionMemory =
|
||||
overrides?.experimental?.sessionMemory ?? defaults?.experimental?.sessionMemory ?? false;
|
||||
const provider = overrides?.provider ?? defaults?.provider ?? "openai";
|
||||
const hasRemote = Boolean(defaults?.remote || overrides?.remote);
|
||||
const remote = hasRemote
|
||||
@@ -81,6 +102,7 @@ function mergeConfig(
|
||||
modelPath: overrides?.local?.modelPath ?? defaults?.local?.modelPath,
|
||||
modelCacheDir: overrides?.local?.modelCacheDir ?? defaults?.local?.modelCacheDir,
|
||||
};
|
||||
const sources = normalizeSources(overrides?.sources ?? defaults?.sources, sessionMemory);
|
||||
const vector = {
|
||||
enabled: overrides?.store?.vector?.enabled ?? defaults?.store?.vector?.enabled ?? true,
|
||||
extensionPath:
|
||||
@@ -114,8 +136,12 @@ function mergeConfig(
|
||||
const minScore = Math.max(0, Math.min(1, query.minScore));
|
||||
return {
|
||||
enabled,
|
||||
sources,
|
||||
provider,
|
||||
remote,
|
||||
experimental: {
|
||||
sessionMemory,
|
||||
},
|
||||
fallback,
|
||||
model,
|
||||
local,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||
import type { SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
import { makeMissingToolResult } from "./session-transcript-repair.js";
|
||||
import { emitSessionTranscriptUpdate } from "../sessions/transcript-events.js";
|
||||
|
||||
type ToolCall = { id: string; name?: string };
|
||||
|
||||
@@ -111,6 +112,12 @@ export function installSessionToolResultGuard(sessionManager: SessionManager): {
|
||||
|
||||
const result = originalAppend(sanitized as never);
|
||||
|
||||
const sessionFile = (sessionManager as { getSessionFile?: () => string | null })
|
||||
.getSessionFile?.();
|
||||
if (sessionFile) {
|
||||
emitSessionTranscriptUpdate(sessionFile);
|
||||
}
|
||||
|
||||
if (toolCalls.length > 0) {
|
||||
for (const call of toolCalls) {
|
||||
pending.set(call.id, call.name);
|
||||
|
||||
@@ -34,7 +34,7 @@ export function createMemorySearchTool(options: {
|
||||
label: "Memory Search",
|
||||
name: "memory_search",
|
||||
description:
|
||||
"Mandatory recall step: semantically search MEMORY.md + memory/*.md before answering questions about prior work, decisions, dates, people, preferences, or todos; returns top snippets with path + lines.",
|
||||
"Mandatory recall step: semantically search MEMORY.md + memory/*.md (and optional session transcripts) before answering questions about prior work, decisions, dates, people, preferences, or todos; returns top snippets with path + lines.",
|
||||
parameters: MemorySearchSchema,
|
||||
execute: async (_toolCallId, params) => {
|
||||
const query = readStringParam(params, "query", { required: true });
|
||||
|
||||
Reference in New Issue
Block a user