From 034b5ce6c1117602b6f27e69ae06a7909da6ece9 Mon Sep 17 00:00:00 2001 From: Miguel de Benito Delgado Date: Fri, 19 Jun 2026 07:44:41 +0200 Subject: [PATCH 1/2] [opencode] Add suport for HINDSIGHT_RETAIN_TAGS --- hindsight-integrations/opencode/README.md | 29 ++++++----- .../opencode/src/config.test.ts | 18 +++++++ hindsight-integrations/opencode/src/config.ts | 8 ++++ .../opencode/src/hooks.test.ts | 48 +++++++++++++++++++ 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/hindsight-integrations/opencode/README.md b/hindsight-integrations/opencode/README.md index a51ccc179..093927a44 100644 --- a/hindsight-integrations/opencode/README.md +++ b/hindsight-integrations/opencode/README.md @@ -102,19 +102,22 @@ Create `~/.hindsight/opencode.json` for persistent configuration: ### Environment Variables -| Variable | Description | Default | -| ----------------------------- | ----------------------------------- | ------------------------------------- | -| `HINDSIGHT_API_URL` | Hindsight API base URL | `https://api.hindsight.vectorize.io` | -| `HINDSIGHT_API_TOKEN` | API key for authentication | (none — required for Hindsight Cloud) | -| `HINDSIGHT_BANK_ID` | Static memory bank ID | `opencode` | -| `HINDSIGHT_AGENT_NAME` | Agent name for dynamic bank IDs | `opencode` | -| `HINDSIGHT_AUTO_RECALL` | Auto-recall on session start | `true` | -| `HINDSIGHT_AUTO_RETAIN` | Auto-retain on session idle | `true` | -| `HINDSIGHT_RETAIN_MODE` | `full-session` or `last-turn` | `full-session` | -| `HINDSIGHT_RECALL_BUDGET` | Recall budget: `low`, `mid`, `high` | `mid` | -| `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens for recall results | `1024` | -| `HINDSIGHT_DYNAMIC_BANK_ID` | Enable dynamic bank ID derivation | `false` | -| `HINDSIGHT_BANK_MISSION` | Bank mission/context | (none) | +| Variable | Description | Default | +| ----------------------------- | -------------------------------------- | ------------------------------------- | +| `HINDSIGHT_API_URL` | Hindsight API base URL | `https://api.hindsight.vectorize.io` | +| `HINDSIGHT_API_TOKEN` | API key for authentication | (none — required for Hindsight Cloud) | +| `HINDSIGHT_BANK_ID` | Static memory bank ID | `opencode` | +| `HINDSIGHT_AGENT_NAME` | Agent name for dynamic bank IDs | `opencode` | +| `HINDSIGHT_AUTO_RECALL` | Auto-recall on session start | `true` | +| `HINDSIGHT_AUTO_RETAIN` | Auto-retain on session idle | `true` | +| `HINDSIGHT_RETAIN_MODE` | `full-session` or `last-turn` | `full-session` | +| `HINDSIGHT_RECALL_BUDGET` | Recall budget: `low`, `mid`, `high` | `mid` | +| `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens for recall results | `1024` | +| `HINDSIGHT_RECALL_TAGS` | Comma-separated, filter recalls | (none) | +| `HINDSIGHT_RECALL_TAGS_MATCH` | Tag match mode: `any`, `all`, `any_strict`, `all_strict` | `any` | +| `HINDSIGHT_RETAIN_TAGS` | Comma-separated, added to every retain | (none) | +| `HINDSIGHT_DYNAMIC_BANK_ID` | Enable dynamic bank ID derivation | `false` | +| `HINDSIGHT_BANK_MISSION` | Bank mission/context | (none) | > **Debug logging** is a config-only option (`"debug": true` in `opencode.json` > plugin options or `~/.hindsight/opencode.json`) — there is intentionally no diff --git a/hindsight-integrations/opencode/src/config.test.ts b/hindsight-integrations/opencode/src/config.test.ts index f1266d186..2dff0f681 100644 --- a/hindsight-integrations/opencode/src/config.test.ts +++ b/hindsight-integrations/opencode/src/config.test.ts @@ -103,6 +103,24 @@ describe("loadConfig", () => { expect(loadConfig().recallMaxTokens).toBe(1024); }); + it("HINDSIGHT_RETAIN_TAGS parses comma-separated tags", () => { + process.env.HINDSIGHT_RETAIN_TAGS = "user:alice, shared , project-x"; + const config = loadConfig(); + expect(config.retainTags).toEqual(["user:alice", "shared", "project-x"]); + }); + + it("HINDSIGHT_RETAIN_TAGS env var overrides plugin option retainTags", () => { + process.env.HINDSIGHT_RETAIN_TAGS = "env-tag"; + const config = loadConfig({ retainTags: ["plugin-tag"] }); + expect(config.retainTags).toEqual(["env-tag"]); + }); + + it("HINDSIGHT_RETAIN_TAGS empty string yields empty array", () => { + process.env.HINDSIGHT_RETAIN_TAGS = ""; + const config = loadConfig(); + expect(config.retainTags).toEqual([]); + }); + it("null plugin options are ignored", () => { const config = loadConfig({ bankId: null, debug: undefined }); expect(config.bankId).toBeNull(); // stays default null diff --git a/hindsight-integrations/opencode/src/config.ts b/hindsight-integrations/opencode/src/config.ts index 3b09426e0..b48eb2860 100644 --- a/hindsight-integrations/opencode/src/config.ts +++ b/hindsight-integrations/opencode/src/config.ts @@ -179,6 +179,14 @@ export function loadConfig(pluginOptions?: Record): HindsightCo config["recallTagsMatch"] = recallTagsMatchEnv; } + const retainTagsEnv = process.env["HINDSIGHT_RETAIN_TAGS"]; + if (retainTagsEnv !== undefined) { + config["retainTags"] = retainTagsEnv + .split(",") + .map((t) => t.trim()) + .filter(Boolean); + } + const result = config as unknown as HindsightConfig; // Validate enum-like fields to catch typos early diff --git a/hindsight-integrations/opencode/src/hooks.test.ts b/hindsight-integrations/opencode/src/hooks.test.ts index 62aa1e2ac..6e1082297 100644 --- a/hindsight-integrations/opencode/src/hooks.test.ts +++ b/hindsight-integrations/opencode/src/hooks.test.ts @@ -74,6 +74,31 @@ describe("event hook — session.idle", () => { expect(opts.metadata.session_id).toBe("sess-1"); }); + it("passes retainTags from config to retain call", async () => { + const client = makeClient(); + const messages = [ + { info: { role: "user" }, parts: [{ type: "text", text: "Hello" }] }, + { info: { role: "assistant" }, parts: [{ type: "text", text: "Hi there" }] }, + ]; + const opencodeClient = makeOpencodeClient(messages); + const state = makeState(); + const hooks = createHooks( + client, + "bank", + makeConfig({ retainTags: ["user:alice", "shared"], retainEveryNTurns: 1 }), + state, + opencodeClient + ); + + await hooks.event({ + event: { type: "session.idle", properties: { sessionID: "sess-1" } }, + }); + + expect(client.retain).toHaveBeenCalledTimes(1); + const opts = client.retain.mock.calls[0][2]; + expect(opts.tags).toEqual(["user:alice", "shared"]); + }); + it("skips retain when autoRetain is false", async () => { const client = makeClient(); const messages = [ @@ -252,6 +277,29 @@ describe("compacting hook", () => { expect(opts.metadata.session_id).toBe("sess-1"); }); + it("pre-compaction retain passes retainTags from config", async () => { + const client = makeClient(); + client.recall.mockResolvedValue({ results: [] }); + const messages = [ + { info: { role: "user" }, parts: [{ type: "text", text: "Hello" }] }, + { info: { role: "assistant" }, parts: [{ type: "text", text: "Hi" }] }, + ]; + const output = { context: [] as string[] }; + const hooks = createHooks( + client, + "bank", + makeConfig({ retainTags: ["user:alice", "auto-tag"] }), + makeState(), + makeOpencodeClient(messages) + ); + + await hooks["experimental.session.compacting"]({ sessionID: "sess-1" }, output); + + expect(client.retain).toHaveBeenCalledTimes(1); + const opts = client.retain.mock.calls[0][2]; + expect(opts.tags).toEqual(["user:alice", "auto-tag"]); + }); + it("pre-compaction retain uses chunked documentId in last-turn mode", async () => { const client = makeClient(); client.recall.mockResolvedValue({ results: [] }); From 185c9061a7e916b6bcf822900011802170e92ae0 Mon Sep 17 00:00:00 2001 From: Miguel de Benito Delgado Date: Fri, 19 Jun 2026 14:25:05 +0200 Subject: [PATCH 2/2] Fix readme formatting --- hindsight-integrations/opencode/README.md | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/hindsight-integrations/opencode/README.md b/hindsight-integrations/opencode/README.md index 093927a44..24ff19ff8 100644 --- a/hindsight-integrations/opencode/README.md +++ b/hindsight-integrations/opencode/README.md @@ -102,22 +102,22 @@ Create `~/.hindsight/opencode.json` for persistent configuration: ### Environment Variables -| Variable | Description | Default | -| ----------------------------- | -------------------------------------- | ------------------------------------- | -| `HINDSIGHT_API_URL` | Hindsight API base URL | `https://api.hindsight.vectorize.io` | -| `HINDSIGHT_API_TOKEN` | API key for authentication | (none — required for Hindsight Cloud) | -| `HINDSIGHT_BANK_ID` | Static memory bank ID | `opencode` | -| `HINDSIGHT_AGENT_NAME` | Agent name for dynamic bank IDs | `opencode` | -| `HINDSIGHT_AUTO_RECALL` | Auto-recall on session start | `true` | -| `HINDSIGHT_AUTO_RETAIN` | Auto-retain on session idle | `true` | -| `HINDSIGHT_RETAIN_MODE` | `full-session` or `last-turn` | `full-session` | -| `HINDSIGHT_RECALL_BUDGET` | Recall budget: `low`, `mid`, `high` | `mid` | -| `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens for recall results | `1024` | -| `HINDSIGHT_RECALL_TAGS` | Comma-separated, filter recalls | (none) | -| `HINDSIGHT_RECALL_TAGS_MATCH` | Tag match mode: `any`, `all`, `any_strict`, `all_strict` | `any` | -| `HINDSIGHT_RETAIN_TAGS` | Comma-separated, added to every retain | (none) | -| `HINDSIGHT_DYNAMIC_BANK_ID` | Enable dynamic bank ID derivation | `false` | -| `HINDSIGHT_BANK_MISSION` | Bank mission/context | (none) | +| Variable | Description | Default | +| ----------------------------- | -------------------------------------------------------- | ------------------------------------- | +| `HINDSIGHT_API_URL` | Hindsight API base URL | `https://api.hindsight.vectorize.io` | +| `HINDSIGHT_API_TOKEN` | API key for authentication | (none — required for Hindsight Cloud) | +| `HINDSIGHT_BANK_ID` | Static memory bank ID | `opencode` | +| `HINDSIGHT_AGENT_NAME` | Agent name for dynamic bank IDs | `opencode` | +| `HINDSIGHT_AUTO_RECALL` | Auto-recall on session start | `true` | +| `HINDSIGHT_AUTO_RETAIN` | Auto-retain on session idle | `true` | +| `HINDSIGHT_RETAIN_MODE` | `full-session` or `last-turn` | `full-session` | +| `HINDSIGHT_RECALL_BUDGET` | Recall budget: `low`, `mid`, `high` | `mid` | +| `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens for recall results | `1024` | +| `HINDSIGHT_RECALL_TAGS` | Comma-separated, filter recalls | (none) | +| `HINDSIGHT_RECALL_TAGS_MATCH` | Tag match mode: `any`, `all`, `any_strict`, `all_strict` | `any` | +| `HINDSIGHT_RETAIN_TAGS` | Comma-separated, added to every retain | (none) | +| `HINDSIGHT_DYNAMIC_BANK_ID` | Enable dynamic bank ID derivation | `false` | +| `HINDSIGHT_BANK_MISSION` | Bank mission/context | (none) | > **Debug logging** is a config-only option (`"debug": true` in `opencode.json` > plugin options or `~/.hindsight/opencode.json`) — there is intentionally no