Skip to content

Commit 7bee442

Browse files
fix(#129): mark m[0]/m[1] history prepends synthetic so they don't suppress titles
OpenCode's auto-title generation (SessionPrompt.ensureTitle) only titles a session when EXACTLY ONE "real" user message exists, where real = `role === "user" && !parts.every(p => p.synthetic)` — it does NOT check `ignored`. Magic Context injects its history blocks by prepending two `role: "user"` messages (m[0] cumulative baseline + m[1] delta) on every transform — including a brand-new session's first turn, where m[0] is an empty placeholder and m[1] is minimal. Those parts had no `synthetic` flag, so a fresh first turn presented THREE real user messages (m0 + m1 + the actual prompt) → `filter(real).length !== 1` → ensureTitle returned without titling, permanently. Reproduced in clean OpenCode (no custom build) in Docker: MC-enabled fresh session never titles ("New session - <ISO>"); plugin-disabled titles fine; disabling auto-search did NOT help (auto-search only appends text, keeping the count at 1) — isolating the m[0]/m[1] prepend as the cause. The git-vs-non-git asymmetry the reporter saw is a timing artifact of the title fiber forking with the shared, about-to-be-transformed `msgs` array. Fix: mark all three prepend sites' text parts `synthetic: true` (the two v2 m[0]/m[1] blocks + the v1 `<session-history>` fallback). `synthetic` keeps them in the real model call — OpenCode's `toModelMessagesEffect` filters on `ignored`, NOT `synthetic`, so history injection is preserved — while excluding them from the title gate. `ignored: true` would have been wrong: it strips parts from the model call and would have removed the injected history from the agent's context. OpenCode-only; Pi has no equivalent title gate. Verified in Docker before/after: the two previously-failing fresh-session cases now title correctly. Prior fix afb19b2 (v0.23.0) only guarded notification posts and never touched this prepend — which is why the issue persisted. Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
1 parent 51fd299 commit 7bee442

1 file changed

Lines changed: 21 additions & 3 deletions

File tree

packages/plugin/src/hooks/magic-context/inject-compartments.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,12 @@ export function renderCompartmentInjection(
536536
const firstMessage = messages[0];
537537
const textPart = firstMessage ? findFirstTextPart(firstMessage.parts) : null;
538538
if (!firstMessage || !textPart || isDroppedPlaceholder(textPart.text)) {
539+
// synthetic: true — injected context, not a real user turn. Keeps it out
540+
// of OpenCode's auto-title gate (issue #129) while still reaching the
541+
// model (toModelMessagesEffect filters `ignored`, not `synthetic`).
539542
messages.unshift({
540543
info: { role: "user", sessionID: sessionId },
541-
parts: [{ type: "text", text: historyBlock }],
544+
parts: [{ type: "text", text: historyBlock, synthetic: true }],
542545
});
543546
} else {
544547
textPart.text = `${historyBlock}\n\n${textPart.text}`;
@@ -2169,14 +2172,29 @@ function prependM0M1Messages(
21692172
m0Text: string,
21702173
m1Text: string,
21712174
): void {
2175+
// `synthetic: true` marks these as injected context, not real user turns.
2176+
// OpenCode's `toModelMessagesEffect` filters on `ignored` (NOT `synthetic`),
2177+
// so the blocks STILL reach the model — but its title-generation gate
2178+
// (`ensureTitle`) counts a message as a real user turn only when not every
2179+
// part is synthetic, and skips titling unless exactly one real user message
2180+
// exists. Without this flag, m[0]+m[1] add two phantom user turns on the
2181+
// first message and permanently suppress the session's auto-title (issue
2182+
// #129). Must NOT use `ignored` here — that would strip the history
2183+
// injection from the real model call.
21722184
messages.unshift(
21732185
{
21742186
info: { role: "user", sessionID: sessionId },
2175-
parts: [{ type: "text", text: m0Text.length > 0 ? m0Text : M0_EMPTY_BODY }],
2187+
parts: [
2188+
{
2189+
type: "text",
2190+
text: m0Text.length > 0 ? m0Text : M0_EMPTY_BODY,
2191+
synthetic: true,
2192+
},
2193+
],
21762194
},
21772195
{
21782196
info: { role: "user", sessionID: sessionId },
2179-
parts: [{ type: "text", text: m1Text }],
2197+
parts: [{ type: "text", text: m1Text, synthetic: true }],
21802198
},
21812199
);
21822200
}

0 commit comments

Comments
 (0)