fix: skip empty untrusted context blocks to prevent model hallucination
untrusted_context_message() now returns None when content is empty or whitespace-only. Previously an empty document would produce a blank UNTRUSTED_SOURCE_DATA wrapper that confused Gemma into thinking the user pasted a placeholder template. Callers already use truthiness guards (if _doc_message:) for insertion, so None propagates cleanly. Two _protected setter sites needed explicit guards added (doc + email paths in agent_loop.py).
This commit is contained in:
parent
6c9e04fa69
commit
60452712b2
2 changed files with 12 additions and 4 deletions
|
|
@ -1504,7 +1504,8 @@ def _build_system_prompt(
|
|||
"knowing the user's personal style."
|
||||
)
|
||||
_doc_message = untrusted_context_message("active editor document", doc_ctx)
|
||||
_doc_message["_protected"] = True
|
||||
if _doc_message:
|
||||
_doc_message["_protected"] = True
|
||||
|
||||
# Auto-detect suggestion mode
|
||||
_last_user_msg = ""
|
||||
|
|
@ -1584,7 +1585,8 @@ def _build_system_prompt(
|
|||
f"open email's sender.\n"
|
||||
)
|
||||
_email_message = untrusted_context_message("active email reader", email_ctx)
|
||||
_email_message["_protected"] = True
|
||||
if _email_message:
|
||||
_email_message["_protected"] = True
|
||||
|
||||
# Inject writing style for any email writing path. This is deliberately
|
||||
# broader than read/list: models may compose via send_email, reply_to_email,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ def _sanitize_label(label: str) -> str:
|
|||
return label
|
||||
|
||||
|
||||
def untrusted_context_message(label: str, content: Any) -> Dict[str, Any]:
|
||||
def untrusted_context_message(label: str, content: Any) -> Dict[str, Any] | None:
|
||||
"""Return an LLM message that keeps retrieved/source text out of system role.
|
||||
|
||||
The template is structured so that *only* the hardcoded
|
||||
|
|
@ -69,9 +69,15 @@ def untrusted_context_message(label: str, content: Any) -> Dict[str, Any]:
|
|||
caller-derived text is placed in the pre-guard trusted framing zone.
|
||||
The source label and the body content are both placed *inside* the
|
||||
guarded block where the LLM treats them as untrusted data.
|
||||
|
||||
Returns None when content is empty or whitespace-only — avoids
|
||||
injecting blank wrapper blocks that confuse the model into thinking
|
||||
the user pasted a placeholder template.
|
||||
"""
|
||||
text = "" if content is None else str(content).strip()
|
||||
if not text:
|
||||
return None
|
||||
safe_label = _sanitize_label(label)
|
||||
text = "" if content is None else str(content)
|
||||
text = _escape_guard_markers(text)
|
||||
return {
|
||||
"role": "user",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue