Skip to content

PreCompact resume snapshot uses bare ctx_search, not the platform tool name #1028

Description

@EvolveAegis

What's wrong

The PreCompact hook builds a resume snapshot that tells the model to retrieve prior context by calling ctx_search(...), but it never passes the platform-specific tool name, so on prefixed platforms the snapshot uses a name that does not match the real tool.

hooks/precompact.mjs:49 calls buildResumeSnapshot(events, { compactCount }) with no searchTool. buildResumeSnapshot (src/session/snapshot.ts) defaults searchTool to the bare string "ctx_search", so whenever the snapshot emits a retrieval hint it uses the bare ctx_search(queries: [...], source: "session-events"). The per-platform PreCompact hooks (hooks/codex/precompact.mjs:44, hooks/kimi/precompact.mjs:52, hooks/vscode-copilot/precompact.mjs:40, hooks/gemini-cli/precompress.mjs:40) repeat the same omission.

On 13 of the 17 known platforms the platform tool-namer produces a prefixed name, so the snapshot's bare ctx_search does not match (for example opencode context-mode_ctx_search, gemini-cli/kimi mcp__context-mode__ctx_search, claude-code mcp__plugin_context-mode_context-mode__ctx_search).

Concrete injection site

The opencode adapter pushes this snapshot straight into model context: src/adapters/opencode/plugin.ts:631-639 calls buildResumeSnapshot(events, { compactCount }) then output.context.push(snapshot), so on opencode the model receives the bare-name hint verbatim.

The plumbing already exists

The sibling sessionstart hooks wire the platform tool name correctly (for example hooks/gemini-cli/sessionstart.mjs passes toolNamer into the directive builder), and snapshot.ts documents searchTool?: string; // platform-specific tool name, default "ctx_search". The PreCompact path was never wired into it, so after a compact context-mode can hand the model two retrieval hints that disagree about the tool name.

Impact (kept narrow)

Recoverable, not a hard break. The separate sessionstart directive still carries the correct platform name as a fallback, and bare-name platforms (cursor/codex/openclaw/pi) are already correct. Where the snapshot is the hint actually surfaced (for example the opencode injection above), the model gets a retrieval cue for a tool name it cannot call.

Reproduce

Verified on main at e27c143. Drives the real exported buildResumeSnapshot plus createToolNamer/KNOWN_PLATFORMS from hooks/core/tool-naming.mjs:

import { buildResumeSnapshot } from "./src/session/snapshot.ts";
import { createToolNamer, KNOWN_PLATFORMS } from "./hooks/core/tool-naming.mjs";

// Real StoredEvent shape (the shape precompact.mjs passes from the DB).
const events = [
  { type: "file_edit", category: "file", data: "src/server.ts", priority: 1, created_at: "2026-07-27T00:00:00Z" },
  { type: "decision", category: "decision", data: "use FTS5 for retrieval", priority: 1, created_at: "2026-07-27T00:00:01Z" },
];

// Mirror hooks/precompact.mjs:49 (no searchTool).
const snap = buildResumeSnapshot(events, { compactCount: 1 });
console.log((snap.match(/\bctx_search\(/g) || []).length); // 2 bare-name calls
console.log(snap.includes("mcp__context-mode__"));          // false (no prefix)

// 13 of 17 platform namers produce a name that differs from the bare hint.
const differ = KNOWN_PLATFORMS.filter(p => createToolNamer(p)("ctx_search") !== "ctx_search");
console.log(differ.length); // 13

Output: 2 bare ctx_search( calls, no platform prefix, 13/17 platform namers differ from the bare name. The one-line fix emits the platform-prefixed name instead.

Fix (one opt per hook, plus the adapter)

Pass the platform name into the snapshot, mirroring the sessionstart path, at hooks/precompact.mjs:49, the four sibling hooks, and the opencode adapter call at src/adapters/opencode/plugin.ts:631:

buildResumeSnapshot(events, { compactCount, searchTool: createToolNamer(platform)("ctx_search") })

Notes

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