Fix search_web over-triggering when user references existing notes
Add a Python fast-path regex (_PRIOR_WORK_REFS) in classify_intent that
detects phrases like "research you did", "note you made", "using your
research", "based on the research" etc. and returns no-tool immediately —
saving the 19s intent LLM call and correctly letting the main model answer
using search_notes/context rather than firing off a web search.
Also tighten the intent prompt rules for search_web: explicitly prohibit
using it for creative/brainstorming requests or when the user references
existing notes, and add a rule that creative/ideation questions ("think of",
"come up with", "brainstorm") always route to null (chat).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -100,9 +100,12 @@ Rules:
|
||||
- "read", "open", "show me", "what does X say", "display", "pull up" a specific note → use get_note with query=<note name>.
|
||||
- "list my notes", "show notes", "recent notes", "browse notes", "notes tagged X" → use list_notes (with optional q or tags).
|
||||
- "tag X with Y", "add tag Y to X", "untag Y from X", "remove tag Y from X" → use update_note with tags=[Y] and tag_mode="add" or "remove".
|
||||
- search_web: user wants a quick factual answer retrieved from the web, without creating a note.
|
||||
Use for brief lookups where a short summary suffices (current version numbers, quick facts,
|
||||
"what is X", "look up X"). Do NOT use when the user wants a detailed written reference.
|
||||
- search_web: user explicitly wants a quick factual answer from the web — current events, version
|
||||
numbers, real-time facts ("what is the latest version of X", "who won the game last night").
|
||||
ONLY use when the information is clearly not in their notes and they need something fresh from
|
||||
the internet. Do NOT use for creative questions, brainstorming, game design, writing help, or
|
||||
when the user is building on content they already have. Do NOT use when the user references
|
||||
their own notes or prior research — use search_notes instead.
|
||||
- research_topic: user wants a comprehensive, multi-section research note created from web sources.
|
||||
Use whenever the user wants to deeply understand, learn about, or get a full written reference
|
||||
on any subject — regardless of how they phrase it. The topic can be anything: technical subjects,
|
||||
@@ -110,12 +113,35 @@ Rules:
|
||||
The "topic" argument should capture the full subject matter of the request.
|
||||
Prefer this over search_web when the user's request implies wanting thorough coverage rather than
|
||||
a quick answer.
|
||||
- For creative/ideation requests ("think of", "come up with", "ideas for", "help me design",
|
||||
"imagine", "brainstorm") use null (chat) — the main model answers these directly. Only route
|
||||
to a tool if the user also explicitly asks to search, look something up, or create/save something.
|
||||
- If the user references notes or research the assistant previously created, prefer search_notes
|
||||
(to retrieve the relevant note) or null (chat) so the main model can use its tools to find it.
|
||||
Never use search_web when existing notes likely contain the answer.
|
||||
- "ack": one short, natural sentence confirming the action (tool path only). Vary phrasing — do not always start with "Let me". Omit (null) for chat-only responses.
|
||||
- Do NOT wrap the JSON in markdown code fences."""
|
||||
|
||||
|
||||
# Fast-path: "Research: <topic>" sent by the Research button.
|
||||
_RESEARCH_PREFIX = re.compile(r"^[Rr]esearch:\s+(.+)", re.DOTALL)
|
||||
|
||||
# When the user refers to work the assistant previously did, they want the main
|
||||
# model to answer using existing context — not a web search. Skip intent and
|
||||
# fall through to the streaming path so the model can call search_notes itself.
|
||||
_PRIOR_WORK_REFS = re.compile(
|
||||
r"\b("
|
||||
r"research (you|that you|we) did"
|
||||
r"|research (you|that you|we) (made|created|compiled|wrote)"
|
||||
r"|note (you|that you|we) (made|created|wrote)"
|
||||
r"|notes (you|that you|we) (made|created|wrote)"
|
||||
r"|using (your|the) research"
|
||||
r"|based on (your|the) research"
|
||||
r"|from (your|the) (research|note|notes)"
|
||||
r")\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
async def classify_intent(
|
||||
user_message: str,
|
||||
@@ -149,6 +175,16 @@ async def classify_intent(
|
||||
ack=f"I'll research that and compile a comprehensive note.",
|
||||
)
|
||||
|
||||
# Fast-path: user references prior assistant work ("research you did", "note you
|
||||
# made", etc.) — this is a request to use existing content, not search the web.
|
||||
# Return no-tool so the main model answers conversationally with search_notes
|
||||
# available if it needs to retrieve the note.
|
||||
if _PRIOR_WORK_REFS.search(user_message):
|
||||
logger.info(
|
||||
"Intent fast-path: prior-work reference detected → skipping tool dispatch"
|
||||
)
|
||||
return IntentResult()
|
||||
|
||||
tool_summary = _build_tool_summary(tools)
|
||||
today = date_type.today().isoformat()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user