Beemer Claude Opus 4.7 commited on
Commit
874ccdf
·
1 Parent(s): 69b9123

Web app: show a corpus-match trust badge (item 8)

Browse files

webapp/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>

Files changed (1) hide show
  1. 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), answer_buf, \
461
- _format_sources(tool_log)
 
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), answer_buf, _format_sources(tool_log)
 
 
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 -----------------------------------------------------------