Skip to content

prompt_submit observations silently dropped: dedup hash ignores prompt content (all prompts share one hash) #1173

Description

@7889545

Summary

prompt_submit observations are silently dropped by the 5-minute dedup window because the dedup hash is computed from ool_input, which does not exist in the prompt_submit payload. All prompt_submit observations for a session share the exact same hash, so within a 300s TTL window only the first user prompt is recorded; every subsequent prompt in that window is discarded, regardless of content.

Root cause

src/functions/dedup.ts (DedupMap):

ts computeHash(sessionId, toolName, toolInput) { const raw = \:\:\; return createHash("sha256").update(raw).digest("hex"); }

mem::observe calls it with d["tool_input"]:

ts const d = typeof payload.data === "object" ? payload.data : {}; const toolName = d["tool_name"] || payload.hookType; dedupHash = dedupMap.computeHash(payload.sessionId, toolName, d["tool_input"]);

The client hook plugin/scripts/prompt-submit.mjs sends data: { prompt: data.prompt ?? data.userPrompt } — there is no ool_input key. So for every prompt_submit the hash input is sessionId:prompt_submit:"", identical for all prompts of the session. TTL_MS = 300_000 (5 min), so within any 5-minute window only the first prompt is kept.

Observed

Claude Code session dbf404f9-..., 10 user prompts over 26 minutes. Only 4 prompt_submit observations were stored (timestamps of stored ones: 16:11:53, 16:18:07, 16:23:23, 16:32:35 — exactly the ones ≥5 min after the previous stored prompt). The other 6 prompts (including substantive follow-ups like "did the hooks fire?" / "is it in the plugin?") were dropped. Verified by replaying the 10 timestamps against the 300s window: 4 kept, 6 deduped.

Impact

  • User prompts are silently missing from memory; recall/summaries lose real conversation context.
  • Clusters of quick follow-up questions (common in interactive sessions) collapse to a single observation.
  • The dedup intended for repeated tool calls (e.g. same bash command) also nukes distinct prompts.

Suggested fix

Use the prompt text as the dedup input for prompt_submit, e.g. in mem::observe:

ts if (payload.hookType === "prompt_submit") { dedupHash = dedupMap.computeHash(payload.sessionId, "prompt_submit", d["prompt"]); } else { dedupHash = dedupMap.computeHash(payload.sessionId, toolName, d["tool_input"]); }

This dedupes literally repeated prompts (e.g. retrying "你好") while keeping distinct follow-ups. Optionally scope the TTL for prompts shorter (e.g. 60s) since the attack surface is small.

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