9662844853
The `learn` tool previously required a `hindsight`/`mnemopi` backend. It now also works when `memory.backend` is `local` (the file-based rollout backend): lessons append to a `learned.md` under the project's memory root, kept separate from the consolidation artifacts so a consolidation pass never clobbers them, and are injected into future sessions alongside the memory summary. - memories: `saveLearnedLesson` (newest-first, deduped, count- and per-field size-capped, secret-redacted, injection-neutralized) with per-path write serialization; `buildMemoryToolDeveloperInstructions` reads `learned.md` and shares one injection budget with the summary; `redactSecrets` extended with GitHub/npm/Slack/Google token prefixes. - local backend: implements `save()`; status reports `writable: true`. - learn tool: `local` execute branch; `createIf`/`isToolAllowed`/auto-include and the standing guidance extended to `local`; local saves tier as a `write` approval. - read-path prompt: renders the learned-lessons block when present. - Lessons are injection-neutralized and secret-redacted on BOTH write and read (they render unescaped into the system prompt). Also moves the auto-learn CHANGELOG entry out of the released [15.12.6] section (a cherry-pick artifact) back under [Unreleased] and notes the local backend. Tests: local storage (format, dedup, cap, redaction incl. provider/delimiter- split tokens, concurrency), read-back (with/without summary, off-gating, raw hand-edited file), tool gating + write-approval tiering.
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
import { resetSettingsForTest, Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
|
import { createMemoryRuntimeContext, resolveMemoryBackend } from "@oh-my-pi/pi-coding-agent/memory-backend";
|
|
|
|
describe("resolveMemoryBackend", () => {
|
|
beforeEach(() => {
|
|
resetSettingsForTest();
|
|
});
|
|
|
|
afterEach(() => {
|
|
resetSettingsForTest();
|
|
});
|
|
|
|
it("returns the hindsight backend when memory.backend is hindsight, regardless of legacy memories.enabled", async () => {
|
|
const a = Settings.isolated({ "memory.backend": "hindsight", "memories.enabled": false });
|
|
const b = Settings.isolated({ "memory.backend": "hindsight", "memories.enabled": true });
|
|
expect((await resolveMemoryBackend(a)).id).toBe("hindsight");
|
|
expect((await resolveMemoryBackend(b)).id).toBe("hindsight");
|
|
});
|
|
|
|
it("exposes inactive status when no session is available", async () => {
|
|
const memory = createMemoryRuntimeContext({ agentDir: "/tmp/agent", cwd: "/tmp/project" });
|
|
|
|
await expect(memory.status()).resolves.toMatchObject({
|
|
backend: "off",
|
|
active: false,
|
|
writable: false,
|
|
searchable: false,
|
|
});
|
|
});
|
|
|
|
it("reports local backend runtime status as writable (lessons) without structured search", async () => {
|
|
const settings = Settings.isolated({ "memory.backend": "local" });
|
|
const memory = createMemoryRuntimeContext({
|
|
agentDir: "/tmp/agent",
|
|
cwd: "/tmp/project",
|
|
session: { settings } as never,
|
|
});
|
|
|
|
await expect(memory.status()).resolves.toMatchObject({
|
|
backend: "local",
|
|
active: true,
|
|
writable: true,
|
|
searchable: false,
|
|
});
|
|
await expect(memory.search("project preference")).resolves.toMatchObject({
|
|
backend: "local",
|
|
count: 0,
|
|
});
|
|
});
|
|
});
|