Skip to content

[bug] Profile injection silently dropped when chatMessage.maxMemories=0 (profile block gated behind non-empty project memories) #438

Closed

Description

@junior-xj97-chan

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-circuit

With 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

  1. Set chatMessage.maxMemories: 0 with injectProfile: true.
  2. Start a new session (first authored user message). No <user_profile> block appears in context; no profile inject log line is emitted.
  3. 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.
  4. 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)

  1. In loadMemoryContext(), when memories.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.

  1. Alternatively, assemble the profile block independently of the project-memory pathway (e.g. call getUserProfileContext from 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

  1. added a commit that references this issue on Oct 28, 2026
    c4c6abe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions