mzidan000 commited on
Commit
367e97d
·
verified ·
1 Parent(s): 0d54892

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. matchday/agent.py +4 -3
  2. matchday/prompts.py +27 -6
  3. matchday/wc2026.py +41 -6
matchday/agent.py CHANGED
@@ -78,9 +78,10 @@ TOOL_SPECS: list[dict[str, Any]] = [
78
  "function": {
79
  "name": "web_search",
80
  "description": (
81
- "Search the web for supplemental FIFA/Vancouver context (kick-off "
82
- "times, venue policies). NOT for prices, flights, hotels, or "
83
- "weather those come from build_trip_packages."
 
84
  ),
85
  "parameters": WebSearchArgs.model_json_schema(),
86
  },
 
78
  "function": {
79
  "name": "web_search",
80
  "description": (
81
+ "Search the web for supplemental FIFA/Vancouver context and "
82
+ "current local facts (kick-off times, venue policies, transit, "
83
+ "current weather right now). NOT for prices, flights, hotels, or "
84
+ "the match-day weather FORECAST — those come from build_trip_packages."
85
  ),
86
  "parameters": WebSearchArgs.model_json_schema(),
87
  },
matchday/prompts.py CHANGED
@@ -77,6 +77,18 @@ Tool-use rules:
77
  - UNDERSTAND FIRST, THEN ACT. Read what the traveler actually wants before
78
  calling a tool. Capture their intent: the origin city/airport, the match,
79
  the dates, the budget, the vibe.
 
 
 
 
 
 
 
 
 
 
 
 
80
  - If the request is clear (you can infer an origin, a match, and at least one
81
  date), call `build_trip_packages` right away — it runs all searches in
82
  parallel and returns 3 scored packages. A match written as "playoff winner",
@@ -90,12 +102,21 @@ Tool-use rules:
90
  the user asks about another city or a non-World-Cup trip, do NOT plan it —
91
  say you specialize in Vancouver 2026 World Cup trips and offer to plan one
92
  of those instead.
93
- - For a factual question (match schedule at BC Place, kickoff time, transit to
94
- the stadium) that `build_trip_packages` does not answer, use `web_search`
95
- (restricted to fifa.com, vancouverfwc26.ca, bcplace.com, translink.ca) and
96
- ANSWER directly from the result. Do not ask for trip details a factual
97
- question does not need. Do NOT use web_search for prices, flights, hotels,
98
- or weather those come from `build_trip_packages`.
 
 
 
 
 
 
 
 
 
99
  - Do not call a tool you already called with identical arguments this turn.
100
  - When you have the packages, write a concise comparison: name each package's
101
  strength (Cheapest / Safest Arrival / Closest to Stadium), cite the real
 
77
  - UNDERSTAND FIRST, THEN ACT. Read what the traveler actually wants before
78
  calling a tool. Capture their intent: the origin city/airport, the match,
79
  the dates, the budget, the vibe.
80
+ - CLASSIFY THE INTENT, then act once. Pick exactly one path:
81
+ (a) TRIP — origin + match + date are present or inferable -> build_trip_packages.
82
+ (b) INCOMPLETE TRIP — a trip is intended but origin OR date is genuinely missing
83
+ -> clarify with ONE specific question offering concrete options.
84
+ (c) FACTUAL / LOCAL question — a question ABOUT the World Cup or Vancouver
85
+ (today's date, the BC Place schedule, kickoff time, how to get to the
86
+ stadium, the CURRENT weather right now, local info) with NO intent to book
87
+ -> answer it directly (see the "FACTUAL / LOCAL questions" rule below); do
88
+ not call build_trip_packages or ask for trip details. "What's the weather
89
+ today in Vancouver?" and "what's today's date?" are (c), not (a).
90
+ (d) OUT OF SCOPE — another destination or a non-World-Cup trip -> decline and
91
+ offer a Vancouver World Cup trip.
92
  - If the request is clear (you can infer an origin, a match, and at least one
93
  date), call `build_trip_packages` right away — it runs all searches in
94
  parallel and returns 3 scored packages. A match written as "playoff winner",
 
102
  the user asks about another city or a non-World-Cup trip, do NOT plan it —
103
  say you specialize in Vancouver 2026 World Cup trips and offer to plan one
104
  of those instead.
105
+ - FACTUAL / LOCAL questions (intent (c) above): answer directly and briefly
106
+ (1-3 lines). If you already have the answer today's date is in your
107
+ instructions; an evening kickoff defaults to 7:00 PM Pacific answer with NO
108
+ tool call. If you need data (the BC Place schedule, a kickoff time, transit,
109
+ the CURRENT weather right now), call `web_search` (preferring authoritative
110
+ sourcesfifa.com / vancouverfwc26.ca / bcplace.com / translink.ca for
111
+ schedule, venue and transit; weather.gc.ca / Environment Canada for current
112
+ weather) and answer from the result. Do
113
+ not ask for trip details a factual question does not need, and do not force
114
+ build_trip_packages for a question that isn't a trip request.
115
+ - TRIP weather, prices, flights and hotels (the match-day FORECAST, airfare, a
116
+ hotel rate) come ONLY from `build_trip_packages` — never from web_search. So
117
+ "what's the weather TODAY in Vancouver?" (current, now) -> web_search;
118
+ "what's the weather for the Canada vs Qatar game?" (a trip forecast) ->
119
+ build_trip_packages. web_search is never used for trip pricing or trip weather.
120
  - Do not call a tool you already called with identical arguments this turn.
121
  - When you have the packages, write a concise comparison: name each package's
122
  strength (Cheapest / Safest Arrival / Closest to Stadium), cite the real
matchday/wc2026.py CHANGED
@@ -60,10 +60,21 @@ _FIXTURES: list[Fixture] = [
60
  Fixture("Bosnia and Herzegovina vs Qatar", date(2026, 6, 24), "Lumen Field", "Seattle", "", "B"),
61
  # Group C — Brazil's group (Brazil, Morocco, Scotland, Haiti)
62
  Fixture("Brazil vs Morocco", date(2026, 6, 13), "MetLife Stadium", "New York / New Jersey", "18:00 ET", "C"),
63
- # Other BC Place (Vancouver) group-stage games
64
  Fixture("Australia vs Türkiye", date(2026, 6, 13), "BC Place", "Vancouver", "21:00 PT", "D"),
65
- Fixture("New Zealand vs Egypt", date(2026, 6, 22), "BC Place", "Vancouver", "", "G"),
66
- Fixture("Argentina vs Austria", date(2026, 6, 22), "BC Place", "Vancouver", "", "G"),
 
 
 
 
 
 
 
 
 
 
 
67
  ]
68
 
69
  # Spoken team-name aliases → canonical token used for matching. Lets "Bosnia"
@@ -87,13 +98,31 @@ def _norm_team(raw: str) -> str:
87
  return _TEAM_ALIASES.get(t, t)
88
 
89
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  def _split_match(match_name: str) -> list[str]:
91
- """Split 'A vs B' into normalized team tokens (any order)."""
 
 
 
 
 
 
92
  import re
93
- parts = re.split(r"\b(?:vs?\.?|versus|[-–])\b", match_name, maxsplit=1, flags=re.IGNORECASE)
94
  if len(parts) != 2:
95
  return []
96
- return [_norm_team(parts[0]), _norm_team(parts[1])]
97
 
98
 
99
  def _teams_match(query_teams: list[str], fixture: Fixture) -> bool:
@@ -107,6 +136,12 @@ def _teams_match(query_teams: list[str], fixture: Fixture) -> bool:
107
  for f in ft:
108
  if q == f or (len(q) >= 3 and (q in f or f in q)):
109
  return f
 
 
 
 
 
 
110
  return None
111
  a, b = hit(query_teams[0]), hit(query_teams[1])
112
  return bool(a and b and a != b)
 
60
  Fixture("Bosnia and Herzegovina vs Qatar", date(2026, 6, 24), "Lumen Field", "Seattle", "", "B"),
61
  # Group C — Brazil's group (Brazil, Morocco, Scotland, Haiti)
62
  Fixture("Brazil vs Morocco", date(2026, 6, 13), "MetLife Stadium", "New York / New Jersey", "18:00 ET", "C"),
63
+ # Group D opener at BC Place (Vancouver) verified Jun 13.
64
  Fixture("Australia vs Türkiye", date(2026, 6, 13), "BC Place", "Vancouver", "21:00 PT", "D"),
65
+ # Group G (Belgium / Egypt / IR Iran / New Zealand) NZ's two BC Place games.
66
+ # NZ vs Egypt is SUNDAY Jun 21 (FIFA match M40), NOT Jun 22 verified against
67
+ # the official FIFA Hospitality Vancouver schedule + Wikipedia Group G
68
+ # (re-checked 2026-06-15). The prior "Jun 22" entry was off by one day, which
69
+ # is exactly the "wrong match data" a user saw. NZ vs Belgium is M64, Fri Jun 26.
70
+ Fixture("New Zealand vs Egypt", date(2026, 6, 21), "BC Place", "Vancouver", "", "G"),
71
+ Fixture("New Zealand vs Belgium", date(2026, 6, 26), "BC Place", "Vancouver", "", "G"),
72
+ # Group J (Argentina's group). Argentina vs Austria is a REAL 2026 fixture but
73
+ # at AT&T Stadium (Dallas/Arlington), NOT Vancouver — corrected from a stale
74
+ # "BC Place / Group G" entry (neither team is in Group G). Kept (truthful) so a
75
+ # user who names it gets an honest "that's in Dallas, not Vancouver" redirect
76
+ # instead of a false "isn't a 2026 fixture".
77
+ Fixture("Argentina vs Austria", date(2026, 6, 22), "AT&T Stadium", "Dallas", "13:00 ET", "J"),
78
  ]
79
 
80
  # Spoken team-name aliases → canonical token used for matching. Lets "Bosnia"
 
98
  return _TEAM_ALIASES.get(t, t)
99
 
100
 
101
+ def _trim_team_suffix(side: str) -> str:
102
+ """Cut a team string at the first standalone dash / 'at' that introduces a
103
+ trailing venue — e.g. 'New Zealand – BC Place' -> 'New Zealand'. Lets a user
104
+ name a match *with* its stadium ('Egypt vs New Zealand – BC Place') still
105
+ resolve instead of being falsely reported as 'not a fixture' (the exact
106
+ 'I added the stadium and it refused' bug)."""
107
+ import re
108
+ side = re.split(r"\s+[-–—]\s+", side, maxsplit=1)[0] # ' – BC Place'
109
+ side = re.split(r"\s+(?:at|@)\s+", side, maxsplit=1, flags=re.IGNORECASE)[0] # ' at BC Place'
110
+ return side.strip()
111
+
112
+
113
  def _split_match(match_name: str) -> list[str]:
114
+ """Split 'A vs B' into normalized team tokens (any order).
115
+
116
+ Each side is trimmed of a trailing venue suffix before normalization, so
117
+ 'Egypt vs New Zealand – BC Place' yields ['egypt','newzealand'] rather than a
118
+ contaminated token ('new zealand – bc place') that fails to match the fixture
119
+ table. Separators accepted: 'vs' / 'v' / 'versus', or a space-padded dash.
120
+ """
121
  import re
122
+ parts = re.split(r"\b(?:vs?\.?|versus)\b|\s+[-–]\s+", match_name, maxsplit=1, flags=re.IGNORECASE)
123
  if len(parts) != 2:
124
  return []
125
+ return [_norm_team(_trim_team_suffix(parts[0])), _norm_team(_trim_team_suffix(parts[1]))]
126
 
127
 
128
  def _teams_match(query_teams: list[str], fixture: Fixture) -> bool:
 
136
  for f in ft:
137
  if q == f or (len(q) >= 3 and (q in f or f in q)):
138
  return f
139
+ # space-insensitive containment: a venue suffix absorbed into the
140
+ # team (e.g. the matcher seeing 'New Zealand BC' from '…BC Place')
141
+ # still matches the canonical 'newzealand'. len(f)>=4 avoids
142
+ # short-token false positives.
143
+ if len(f) >= 4 and f in q.replace(" ", ""):
144
+ return f
145
  return None
146
  a, b = hit(query_teams[0]), hit(query_teams[1])
147
  return bool(a and b and a != b)