feat(opencode): add recallTags and recallTagsMatch config options (#969)

This commit is contained in:
Ben 2026-04-10 11:14:59 -04:00 committed by GitHub
parent c05c491d77
commit b57e337fa2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 37 additions and 0 deletions

View file

@ -76,6 +76,9 @@ This ensures memories survive context window trimming.
"autoRecall": true, "autoRecall": true,
"autoRetain": true, "autoRetain": true,
"recallBudget": "mid", "recallBudget": "mid",
"recallTags": [],
"recallTagsMatch": "any",
"retainTags": [],
"retainEveryNTurns": 10, "retainEveryNTurns": 10,
"debug": false "debug": false
}] }]
@ -108,6 +111,8 @@ Create `~/.hindsight/opencode.json` for persistent configuration that applies ac
| `HINDSIGHT_RETAIN_MODE` | `full-session` or `last-turn` | `full-session` | | `HINDSIGHT_RETAIN_MODE` | `full-session` or `last-turn` | `full-session` |
| `HINDSIGHT_RECALL_BUDGET` | Recall budget: `low`, `mid`, `high` | `mid` | | `HINDSIGHT_RECALL_BUDGET` | Recall budget: `low`, `mid`, `high` | `mid` |
| `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens for recall results | `1024` | | `HINDSIGHT_RECALL_MAX_TOKENS` | Max tokens for recall results | `1024` |
| `HINDSIGHT_RECALL_TAGS` | Comma-separated tags to filter recall results | |
| `HINDSIGHT_RECALL_TAGS_MATCH` | Tag match mode: `any`, `all`, `any_strict`, `all_strict` | `any` |
| `HINDSIGHT_DYNAMIC_BANK_ID` | Enable dynamic bank ID derivation | `false` | | `HINDSIGHT_DYNAMIC_BANK_ID` | Enable dynamic bank ID derivation | `false` |
| `HINDSIGHT_BANK_MISSION` | Bank mission/context for reflect | | | `HINDSIGHT_BANK_MISSION` | Bank mission/context for reflect | |
| `HINDSIGHT_DEBUG` | Enable debug logging to stderr | `false` | | `HINDSIGHT_DEBUG` | Enable debug logging to stderr | `false` |

View file

@ -21,6 +21,8 @@ export interface HindsightConfig {
recallContextTurns: number; recallContextTurns: number;
recallMaxQueryChars: number; recallMaxQueryChars: number;
recallPromptPreamble: string; recallPromptPreamble: string;
recallTags: string[];
recallTagsMatch: 'any' | 'all' | 'any_strict' | 'all_strict';
// Retain // Retain
autoRetain: boolean; autoRetain: boolean;
@ -56,6 +58,8 @@ const DEFAULTS: HindsightConfig = {
recallTypes: ['world', 'experience'], recallTypes: ['world', 'experience'],
recallContextTurns: 1, recallContextTurns: 1,
recallMaxQueryChars: 800, recallMaxQueryChars: 800,
recallTags: [],
recallTagsMatch: 'any',
recallPromptPreamble: recallPromptPreamble:
'Relevant memories from past conversations (prioritize recent when ' + 'Relevant memories from past conversations (prioritize recent when ' +
'conflicting). Only use memories that are directly useful to continue ' + 'conflicting). Only use memories that are directly useful to continue ' +
@ -156,6 +160,19 @@ export function loadConfig(pluginOptions?: Record<string, unknown>): HindsightCo
} }
} }
// Array env vars (comma-separated)
const recallTagsEnv = process.env['HINDSIGHT_RECALL_TAGS'];
if (recallTagsEnv !== undefined) {
config['recallTags'] = recallTagsEnv
.split(',')
.map((t) => t.trim())
.filter(Boolean);
}
const recallTagsMatchEnv = process.env['HINDSIGHT_RECALL_TAGS_MATCH'];
if (recallTagsMatchEnv !== undefined) {
config['recallTagsMatch'] = recallTagsMatchEnv;
}
const result = config as unknown as HindsightConfig; const result = config as unknown as HindsightConfig;
// Validate enum-like fields to catch typos early // Validate enum-like fields to catch typos early
@ -168,6 +185,15 @@ export function loadConfig(pluginOptions?: Record<string, unknown>): HindsightCo
result.retainMode = 'full-session'; result.retainMode = 'full-session';
} }
const VALID_TAGS_MATCH = ['any', 'all', 'any_strict', 'all_strict'];
if (!VALID_TAGS_MATCH.includes(result.recallTagsMatch)) {
console.error(
`[Hindsight] Unknown recallTagsMatch "${result.recallTagsMatch}" — ` +
`valid: ${VALID_TAGS_MATCH.join(', ')}. Falling back to "any".`,
);
result.recallTagsMatch = 'any';
}
const VALID_BUDGETS = ['low', 'mid', 'high']; const VALID_BUDGETS = ['low', 'mid', 'high'];
if (!VALID_BUDGETS.includes(result.recallBudget)) { if (!VALID_BUDGETS.includes(result.recallBudget)) {
console.error( console.error(

View file

@ -95,6 +95,8 @@ export function createHooks(
budget: config.recallBudget as 'low' | 'mid' | 'high', budget: config.recallBudget as 'low' | 'mid' | 'high',
maxTokens: config.recallMaxTokens, maxTokens: config.recallMaxTokens,
types: config.recallTypes, types: config.recallTypes,
tags: config.recallTags.length ? config.recallTags : undefined,
tagsMatch: config.recallTags.length ? config.recallTagsMatch : undefined,
}); });
const results = response.results || []; const results = response.results || [];

View file

@ -9,6 +9,8 @@ export function makeConfig(overrides: Partial<HindsightConfig> = {}): HindsightC
recallContextTurns: 1, recallContextTurns: 1,
recallMaxQueryChars: 800, recallMaxQueryChars: 800,
recallPromptPreamble: '', recallPromptPreamble: '',
recallTags: [],
recallTagsMatch: 'any',
autoRetain: true, autoRetain: true,
retainMode: 'full-session', retainMode: 'full-session',
retainEveryNTurns: 10, retainEveryNTurns: 10,

View file

@ -68,6 +68,8 @@ export function createTools(
budget: config.recallBudget as 'low' | 'mid' | 'high', budget: config.recallBudget as 'low' | 'mid' | 'high',
maxTokens: config.recallMaxTokens, maxTokens: config.recallMaxTokens,
types: config.recallTypes, types: config.recallTypes,
tags: config.recallTags.length ? config.recallTags : undefined,
tagsMatch: config.recallTags.length ? config.recallTagsMatch : undefined,
}); });
const results = response.results || []; const results = response.results || [];