mzidan000 commited on
Commit
15e0487
·
verified ·
1 Parent(s): a23fe77

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +93 -0
app.py CHANGED
@@ -47,6 +47,7 @@ from matchday.agent_trace import ( # noqa: E402
47
  )
48
  from matchday.intent import parse_intent # noqa: E402
49
  from matchday.models import TripRequest # noqa: E402
 
50
  from matchday.prompts import EXPLANATION_HINT # noqa: E402
51
  from matchday.render import render_full # noqa: E402
52
  from matchday.trip_tool import build_trip_packages, format_for_nemotron # noqa: E402
@@ -125,6 +126,78 @@ def _notice_status(result, *keywords: str) -> str:
125
  return "fallback" if any(k in blob for k in keywords) else "done"
126
 
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  def _finalize_trace(trace: AgentTrace, trip, result, built_by: str) -> None:
129
  """Populate the final intent/grounding/evidence/ranking/outcome on the trace.
130
 
@@ -242,6 +315,26 @@ async def plan_trip(user_text: str) -> str:
242
  yield _ev(type="progress", step="read", status="done", text="Read your request")
243
  yield _ev(type="progress", step="extract", status="running", text="Understanding your trip")
244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  agent = None
246
  if USE_AGENT:
247
  try:
 
47
  )
48
  from matchday.intent import parse_intent # noqa: E402
49
  from matchday.models import TripRequest # noqa: E402
50
+ from matchday.wc2026 import resolve_match # noqa: E402
51
  from matchday.prompts import EXPLANATION_HINT # noqa: E402
52
  from matchday.render import render_full # noqa: E402
53
  from matchday.trip_tool import build_trip_packages, format_for_nemotron # noqa: E402
 
126
  return "fallback" if any(k in blob for k in keywords) else "done"
127
 
128
 
129
+ def _precheck_unrecognized_match(user_text: str):
130
+ """Generic pre-agent fixture validator (grounding honesty, option 1).
131
+
132
+ Deterministically parse the request and ground the named match against the
133
+ verified 2026 fixture table BEFORE the agent picks a tool. If the user named
134
+ a matchup that isn't a real 2026 fixture, return ``(refusal_note, trip)`` so
135
+ ``plan_trip`` can refuse honestly with the closest real alternatives and stop
136
+ — without ever invoking the agent loop.
137
+
138
+ Why this exists: Nemotron routes its own tools and, for some non-fixture
139
+ matchups (e.g. "Canada vs Morocco"), can non-deterministically choose
140
+ ``clarify`` over ``build_trip_packages``. When it does, the grounding-refusal
141
+ path (the "isn't a 2026 fixture … Canada plays: …" note produced inside the
142
+ build tool) never runs, so the demo promises a refusal it never delivers.
143
+ Grounding the match deterministically up front guarantees every non-fixture
144
+ match is refused honestly, regardless of how the model routes.
145
+
146
+ Returns ``(note, trip_request)`` when a match is named AND unrecognized;
147
+ ``None`` otherwise (no match named, parse failed, or the match IS real —
148
+ proceed to the normal agent path). Never raises.
149
+ """
150
+ try:
151
+ parsed = parse_intent(user_text)
152
+ except Exception: # noqa: BLE001 — must never break the turn
153
+ return None
154
+ trip = getattr(parsed, "trip_request", None)
155
+ match_name = (getattr(trip, "match_name", "") or "") if trip is not None else ""
156
+ if not match_name or match_name == "the match": # _find_match's fallback sentinel
157
+ return None
158
+ match_name = _clean_match_name(match_name) # drop trailing month ("Morocco June" -> "Morocco")
159
+ try:
160
+ res = resolve_match(match_name)
161
+ except Exception: # noqa: BLE001
162
+ return None
163
+ if res.recognized or not res.note:
164
+ return None
165
+ try: # carry the CLEANED name onto the trip so the trace drawer matches the note
166
+ trip = trip.model_copy(update={"match_name": match_name})
167
+ except Exception: # noqa: BLE001
168
+ pass
169
+ return res.note, trip
170
+
171
+
172
+ _MONTH_TOKENS = {
173
+ "january", "february", "march", "april", "may", "june",
174
+ "july", "august", "september", "october", "november", "december",
175
+ }
176
+
177
+
178
+ def _clean_match_name(name: str) -> str:
179
+ """Strip a trailing month token from each team in an 'A vs B' match name.
180
+
181
+ ``parse_intent``'s ``_find_match`` greedily appends the next capitalized word
182
+ to a team name, so 'Canada vs Morocco June 18' parses to 'Canada vs Morocco
183
+ June' — the month leaks into the team and would surface in the refusal note
184
+ as "Morocco June plays: Brazil". Trimming trailing month tokens restores the
185
+ real team names for a clean note. Conservative: only strips trailing month
186
+ tokens, leaves everything else intact (multi-word teams unaffected).
187
+ """
188
+ if " vs " not in name:
189
+ return name
190
+
191
+ def _strip(trial: str) -> str:
192
+ parts = trial.split()
193
+ while parts and parts[-1].lower().rstrip(".") in _MONTH_TOKENS:
194
+ parts.pop()
195
+ return " ".join(parts)
196
+
197
+ a, b = name.split(" vs ", 1)
198
+ return f"{_strip(a)} vs {_strip(b)}"
199
+
200
+
201
  def _finalize_trace(trace: AgentTrace, trip, result, built_by: str) -> None:
202
  """Populate the final intent/grounding/evidence/ranking/outcome on the trace.
203
 
 
315
  yield _ev(type="progress", step="read", status="done", text="Read your request")
316
  yield _ev(type="progress", step="extract", status="running", text="Understanding your trip")
317
 
318
+ # ── Generic pre-agent fixture validator (grounding honesty). Ground the named
319
+ # match deterministically BEFORE the agent picks a tool: a non-real 2026
320
+ # fixture is refused with the closest real alternatives and we stop, so the
321
+ # refusal never depends on Nemotron choosing build_trip_packages over clarify.
322
+ _pre = _precheck_unrecognized_match(user_text)
323
+ if _pre is not None:
324
+ _refusal_note, _pre_trip = _pre
325
+ trace.set_intent(_pre_trip)
326
+ trace.set_grounding(recognized=False, note=_refusal_note)
327
+ trace.set_outcome(
328
+ mode="deterministic", status="clarify",
329
+ notes=["Pre-agent fixture check: named match is not a real 2026 fixture."],
330
+ model=_TRACE_MODEL, rounds=0,
331
+ )
332
+ yield _ev(type="trace", data=trace.to_dict()) # grounding-refusal proof
333
+ yield _ev(type="progress", step="extract", status="done", text="Match checked")
334
+ yield _ev(type="progress", step="ready", status="fallback", text="Match not found")
335
+ yield _ev(type="clarify", text=_refusal_note)
336
+ return
337
+
338
  agent = None
339
  if USE_AGENT:
340
  try: