Beemer Claude Opus 4.7 commited on
Commit ·
874ccdf
1
Parent(s): 69b9123
Web app: show a corpus-match trust badge (item 8)
Browse fileswebapp/app.py _match_badge reads the MCP search tools' own signals -- the
'RETRIEVAL CAUTION' weak-match note and the 'No results matched' message the
server already emits -- and renders a badge above the answer: "Grounded" on a
direct match, "Weak match" when CanLex may lack a provision on point, or "No
matching source found". The agentic loop previously flattened results to prose,
so a public user got no sense of how well the corpus actually matched their
question. Reuses an existing signal; no new dependency.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- webapp/app.py +26 -3
webapp/app.py
CHANGED
|
@@ -364,6 +364,26 @@ def _summarize_call(name: str, args: dict) -> str:
|
|
| 364 |
return f"Calling {name}"
|
| 365 |
|
| 366 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
def _format_sources(tool_log: list[tuple[str, dict, str]]) -> str:
|
| 368 |
"""Render every tool call's output as one Markdown document for display."""
|
| 369 |
if not tool_log:
|
|
@@ -457,8 +477,9 @@ async def _agentic_answer(question: str):
|
|
| 457 |
f"{finish_reason!s}). If this is MAX_TOKENS, "
|
| 458 |
"raise MAX_OUTPUT_TOKENS in app.py.")
|
| 459 |
answer_buf += turn_text
|
| 460 |
-
yield status_md(thinking=False),
|
| 461 |
-
|
|
|
|
| 462 |
return
|
| 463 |
|
| 464 |
# Tool turn. If the model emitted a commentary fragment before
|
|
@@ -507,7 +528,9 @@ async def _agentic_answer(question: str):
|
|
| 507 |
_format_sources(tool_log))
|
| 508 |
answer_buf += turn_text or \
|
| 509 |
"_(no answer produced after the tool-call budget was exhausted)_"
|
| 510 |
-
yield status_md(thinking=False),
|
|
|
|
|
|
|
| 511 |
|
| 512 |
|
| 513 |
# --- Gradio handler -----------------------------------------------------------
|
|
|
|
| 364 |
return f"Calling {name}"
|
| 365 |
|
| 366 |
|
| 367 |
+
def _match_badge(tool_log: list[tuple[str, dict, str]]) -> str:
|
| 368 |
+
"""A trust badge reflecting how well CanLex's corpus matched the question,
|
| 369 |
+
read from the search tools' own signals: the MCP server prepends a
|
| 370 |
+
'RETRIEVAL CAUTION' note on a weak semantic match and a 'No results matched'
|
| 371 |
+
message when nothing is found. Public users get no sense of this otherwise --
|
| 372 |
+
the agent flattens results to prose -- so surface it explicitly."""
|
| 373 |
+
searches = [out for name, _a, out in tool_log
|
| 374 |
+
if name == "canlex_search_legislation"]
|
| 375 |
+
if not searches:
|
| 376 |
+
return ""
|
| 377 |
+
if all("No results matched" in s for s in searches):
|
| 378 |
+
return ("> ⚠️ **No matching CanLex source found** — this question may be "
|
| 379 |
+
"outside the corpus; treat the answer with extra caution.\n\n")
|
| 380 |
+
if any("RETRIEVAL CAUTION" in s for s in searches):
|
| 381 |
+
return ("> ⚠️ **Weak match** — CanLex may not contain a provision "
|
| 382 |
+
"directly on point; verify the answer against primary sources.\n\n")
|
| 383 |
+
return ("> ✅ **Grounded** — based on CanLex sources that directly matched "
|
| 384 |
+
"the question.\n\n")
|
| 385 |
+
|
| 386 |
+
|
| 387 |
def _format_sources(tool_log: list[tuple[str, dict, str]]) -> str:
|
| 388 |
"""Render every tool call's output as one Markdown document for display."""
|
| 389 |
if not tool_log:
|
|
|
|
| 477 |
f"{finish_reason!s}). If this is MAX_TOKENS, "
|
| 478 |
"raise MAX_OUTPUT_TOKENS in app.py.")
|
| 479 |
answer_buf += turn_text
|
| 480 |
+
yield (status_md(thinking=False),
|
| 481 |
+
_match_badge(tool_log) + answer_buf,
|
| 482 |
+
_format_sources(tool_log))
|
| 483 |
return
|
| 484 |
|
| 485 |
# Tool turn. If the model emitted a commentary fragment before
|
|
|
|
| 528 |
_format_sources(tool_log))
|
| 529 |
answer_buf += turn_text or \
|
| 530 |
"_(no answer produced after the tool-call budget was exhausted)_"
|
| 531 |
+
yield (status_md(thinking=False),
|
| 532 |
+
_match_badge(tool_log) + answer_buf,
|
| 533 |
+
_format_sources(tool_log))
|
| 534 |
|
| 535 |
|
| 536 |
# --- Gradio handler -----------------------------------------------------------
|