Repository navigation
Description
Environment
- opencode-mem 2.34.0 (npm install via OpenCode V2), Windows 11 x64, embedded Turso
- Relevant config:
chatMessage.enabled: true,injectProfile: true,chatMessage.maxMemories: 0,autoCaptureEnabled: true
Summary
With chatMessage.maxMemories: 0, the <user_profile> context block is never injected, and profileInjections in the Stats view stays 0 for every session. The profile block is intended to be independent of project-memory injection (it only checks injectProfile), but the current call path short-circuits before it is ever built.
Root cause
loadMemoryContext() lists project memories first and returns early when the list is empty:
// dist/index.js (v2.34.0)
const listResult = await memoryClient.listMemories(tags.project.tag, CONFIG.chatMessage.maxMemories); // :570
...
if (memories.length === 0) // :579
return ""; // :580 <-- short-circuitWith maxMemories: 0 the listing is empty, so formatContextForPrompt() — the only place the <user_profile> block is assembled (dist/services/context.js:4-29, gated solely by CONFIG.injectProfile at :6) — is never called. As a result log("profile inject", ...) (dist/services/user-profile/profile-context.js:98) never emits, which is why the Stats counter profileInjections (dist/services/stats-service.js:30-31) stays at 0.
Expected behavior
When injectProfile is enabled but there are zero project memories to inject, formatContextForPrompt() should still be called with an empty project-memories payload so the profile block is delivered on its own.
Repro
- Set
chatMessage.maxMemories: 0withinjectProfile: true. - Start a new session (first authored user message). No
<user_profile>block appears in context; noprofile injectlog line is emitted. - Stats page: profile-injection count stays 0, while compaction injections (separate pathway, own log line
Compaction memory injected) continue to be recorded — only the first-message pathway is affected. - Profile learning keeps running normally in the background, so the disconnect is invisible except via the Stats page (or an agent that no longer "knows" the user's preferences).
Observed in production
Profile injections dropped to zero starting the first day after upgrading to 2.33.x and continuing under 2.34.0 (verified line-by-line in the 2.34.0 dist). A previous local build (2.26.x era) included a small local patch that skipped the project-memory search while still calling formatContextForPrompt — i.e. exactly the fix suggested below — and with the same config it produced several profile injections per day.
Suggested fix (either works)
- In
loadMemoryContext(), whenmemories.length === 0, still build the context with an empty payload:
return formatContextForPrompt(userId, { results: [], total: 0, timing: 0 });formatContextForPrompt already handles projectResults.length === 0 (context.js:13) and then emits only the <user_profile> block. Users with no profile are unaffected because getUserProfileContext returns null and the block is skipped.
- Alternatively, assemble the profile block independently of the project-memory pathway (e.g. call
getUserProfileContextfrom the caller side and merge).
Why not a config change?
maxMemories > 0 would restore injection, but the list semantics ("N most recent", non-semantic) reintroduce stale context that 0 was chosen to avoid — and it still couples two independent features. Since injectProfile is a standalone config key, the gating looks unintended.
Activity
fix(context): inject profile when project memories are empty (tickern…