Skip to content

Commit 280b4c7

Browse files
committed
fix(hooks): make the recall opener survive tool use
real-world test: on tool-heavy prompts the model explored the codebase and dropped the soft "open your reply with" instruction from its final message, so recall ran invisibly — the exact symptom the banners exist to kill. verified on a live project: memory-shaped prompts opened with "From vouch memory:", tool-heavy ones did not. state the opener as a hard output contract in all three banners: the final reply MUST open with the exact words, even if the model uses tools or explores first. re-verified end-to-end on the same project — the previously-failing prompt now opens with "From vouch memory:", grounds in cited ids, and still does its tool exploration afterwards.
1 parent 756ff19 commit 280b4c7

2 files changed

Lines changed: 18 additions & 9 deletions

File tree

src/vouch/hooks.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,9 @@ def build_claude_prompt_hook(store: KBStore, stdin_text: str) -> str:
185185
# was consulted, not silence that looks like vouch did nothing.
186186
return _envelope(
187187
"[vouch memory] I searched the project's vouch knowledge base for this "
188-
'prompt and found nothing relevant. Open your reply with "Nothing in '
189-
'vouch on this." then answer from your own knowledge.'
188+
"prompt and found nothing relevant. Your final reply MUST open with "
189+
'the exact words "Nothing in vouch on this." — even if you use tools '
190+
"or explore the codebase first — then answer from your own knowledge."
190191
)
191192

192193
sc_enabled, min_conf = short_circuit_cfg(cfg)
@@ -201,16 +202,24 @@ def build_claude_prompt_hook(store: KBStore, stdin_text: str) -> str:
201202
'prompt, reply with ONLY "From vouch memory:" then the relevant '
202203
"item(s) verbatim and their [ev-...] id(s), and STOP -- no extra "
203204
"reasoning, caveats, or tool calls. If they do NOT fully answer it, "
204-
'continue normally: open with "From vouch memory:" and ground in them.'
205+
"continue normally: ground in them, and your final reply MUST still "
206+
'open with "From vouch memory:" even after tool use.'
205207
"\n\n" + body
206208
)
207209
else:
210+
# The opener is a hard output contract, not a suggestion: models that
211+
# explore with tools before answering routinely drop soft "open your
212+
# reply with" phrasing from their final message (observed in the field
213+
# on tool-heavy prompts), so state it as a MUST that survives tool use.
208214
block = (
209215
"[vouch memory] I searched the project's vouch knowledge base for this "
210-
"prompt. Approved, cited items are below. Before you reason on your own: "
211-
'open your reply with "From vouch memory:" and ground your answer in the '
212-
"relevant item(s), citing each id in [brackets]. If none are actually "
213-
'relevant, say "Nothing relevant in vouch on this" and then answer from '
216+
"prompt. Approved, cited items are below — check them BEFORE reasoning "
217+
"or exploring on your own, and ground your answer in the relevant "
218+
"item(s), citing each id in [brackets]. Your final reply MUST open "
219+
'with the exact words "From vouch memory:" — even if you use tools or '
220+
"explore the codebase first, that opener comes before everything else "
221+
"in your answer. If none of the items are actually relevant, open "
222+
'with "Nothing relevant in vouch on this" instead and answer from '
214223
"your own knowledge.\n\n" + body
215224
)
216225
return _envelope(block)

tests/test_hooks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def test_relevant_prompt_banner_instructs_from_vouch_memory(
5555
out = hooks.build_claude_prompt_hook(store, json.dumps({"prompt": "when do deploys run"}))
5656
ctx = json.loads(out)["hookSpecificOutput"]["additionalContext"]
5757
assert ctx.startswith("[vouch memory]")
58-
assert 'open your reply with "From vouch memory:"' in ctx
58+
assert 'MUST open with the exact words "From vouch memory:"' in ctx
5959

6060

6161
def test_raw_non_json_stdin_is_tolerated(store: KBStore, monkeypatch: pytest.MonkeyPatch) -> None:
@@ -117,7 +117,7 @@ def test_short_circuit_never_fires_for_action_prompts(
117117
out = hooks.build_claude_prompt_hook(store, json.dumps({"prompt": "fix the deploy pipeline"}))
118118
ctx = json.loads(out)["hookSpecificOutput"]["additionalContext"]
119119
assert "high-confidence match" not in ctx
120-
assert 'open your reply with "From vouch memory:"' in ctx
120+
assert 'MUST open with the exact words "From vouch memory:"' in ctx
121121

122122

123123
def test_short_circuit_off_by_default(

0 commit comments

Comments
 (0)