Skip to content

opencode plugin: auto-title generation consumes the once-per-session memory injection — main conversation never gets context #1184

Description

@liangrud

Summary

With the OpenCode plugin (plugin/opencode/agentmemory-capture.ts), the memory-context injection ("once per session", gated by contextInjectedSessions) is consumed by OpenCode's auto-title generation request instead of the real conversation's first turn. The main conversation therefore never receives <agentmemory-instructions> or <agentmemory-context>.

Environment

  • agentmemory: current main
  • OpenCode plugin: plugin/opencode/agentmemory-capture.ts
  • Observed in the opencode request flow itself (see Root cause).

Root cause

When a new session gets its first user message, opencode runs two concurrent LLM requests, both firing experimental.chat.system.transform:

  1. Auto-title generation — forked in the session loop at packages/opencode/src/session/prompt.ts:1132-1139; calls llm.stream with sessionID: <the same session> (prompt.ts:233) → LLMRequestPrep.prepare → triggers the hook with { sessionID, model } (src/session/llm/request.ts:69-73).
  2. The real user turnprocessor.ts:640 → same prepare → same hook, same sessionID.

Both carry the same sessionID, and the plugin's contextInjectedSessions gate is keyed only on sessionID. Whichever request reaches prepare first consumes the once-per-session injection — and the title request (tiny system prompt, small model) virtually always wins the race. The plugin cannot tell them apart.

Evidence

Server log (gen_ai.input.messages, two requests for the same first message):

  • title request system prompt: You are a title generator... + <agentmemory-instructions> (+ context) ← injected here
  • build / main request system prompt: only the base instructions — no <agentmemory-instructions> / <agentmemory-context>

Suggested fix (upstream, opencode side)

Add the agent name to the experimental.chat.system.transform hook input at packages/opencode/src/session/llm/request.ts:70 (and the plugin type in packages/plugin/src/index.ts), e.g. { sessionID, model, agent: input.agent.name }. Plugins can then reliably skip native/internal agents (input.agent === "title", and future internal agents) instead of string-matching the title prompt. This is additive and backward-compatible for existing plugin consumers.

Workaround (plugin side, brittle)

Plugins can skip the title request by matching the title-generator prompt in output.system[0] (e.g. /^You are (?:a|the) title generator/i), but that silently regresses if opencode ever rewrites the title prompt.

Related

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