support fixtures search for date range, prompt engineering

This commit is contained in:
Steve Androulakis
2025-02-15 07:35:14 -08:00
parent 6a43c28a84
commit 4776d29d0f
4 changed files with 45 additions and 34 deletions

View File

@@ -15,7 +15,7 @@ goal_match_train_invoice = AgentGoal(
create_invoice_tool, create_invoice_tool,
], ],
description="Help the user book trains to a premier league match. The user lives in London. Gather args for these tools in order: " description="Help the user book trains to a premier league match. The user lives in London. Gather args for these tools in order: "
"1. SearchFixtures: Search for fixtures for a team in a given month" "1. SearchFixtures: Search for fixtures for a team within a specified date range."
"2. SearchTrains: Search for trains to the city of the match and list them for the customer to choose from" "2. SearchTrains: Search for trains to the city of the match and list them for the customer to choose from"
"3. BookTrains: Book the train tickets" "3. BookTrains: Book the train tickets"
"4. CreateInvoice: Proactively offer to create a simple invoice for the cost of the flights and train tickets", "4. CreateInvoice: Proactively offer to create a simple invoice for the cost of the flights and train tickets",
@@ -23,9 +23,9 @@ goal_match_train_invoice = AgentGoal(
example_conversation_history="\n ".join( example_conversation_history="\n ".join(
[ [
"user: I'd like to travel to a premier league match", "user: I'd like to travel to a premier league match",
"agent: Sure! Let's start by finding an match you'd like to attend. I know about Premier League fixtures in the UK. Could you tell me which team and month you're interested in?", "agent: Sure! Let's start by finding a match you'd like to attend. I know about Premier League fixtures in the UK. Could you tell me which team and what date range you're interested in?"
"user: Wolves in May please", "user: Wolves between mid-April and the first week of May, please."
"agent: Great! Let's find a match for Wolverhampton Wanderers FC in May.", "agent: Great! Let's find fixtures for Wolverhampton Wanderers FC between 2025-04-15 and 2025-05-05."
"user_confirmed_tool_run: <user clicks confirm on SearchFixtures tool, passing the full team name as an input>", "user_confirmed_tool_run: <user clicks confirm on SearchFixtures tool, passing the full team name as an input>",
'tool_result: SearchFixtures responds in this JSON format and the results are parsed by the agent below {"fixtures": [{"awayTeam": "West Ham United FC","date": "2025-04-01","homeTeam": "Wolverhampton Wanderers FC"},...,' 'tool_result: SearchFixtures responds in this JSON format and the results are parsed by the agent below {"fixtures": [{"awayTeam": "West Ham United FC","date": "2025-04-01","homeTeam": "Wolverhampton Wanderers FC"},...,'
"agent: I found 4 Wolves matches in May 2025: 1. Man City vs Wolves (Away) - May 3 2. Wolves vs Brighton (Home) - May 10 3. Crystal Palace vs Wolves (Away) - May 18 4. Wolves vs Brentford (Home) - May 25 Which match would you like to attend? I'll help you find trains from London.", "agent: I found 4 Wolves matches in May 2025: 1. Man City vs Wolves (Away) - May 3 2. Wolves vs Brighton (Home) - May 10 3. Crystal Palace vs Wolves (Away) - May 18 4. Wolves vs Brentford (Home) - May 25 Which match would you like to attend? I'll help you find trains from London.",

View File

@@ -3,57 +3,63 @@ import requests
from datetime import datetime from datetime import datetime
from dotenv import load_dotenv from dotenv import load_dotenv
BASE_URL = 'https://api.football-data.org/v4' BASE_URL = "https://api.football-data.org/v4"
def search_fixtures(args: dict) -> dict: def search_fixtures(args: dict) -> dict:
load_dotenv(override=True) load_dotenv(override=True)
api_key = os.getenv("FOOTBALL_DATA_API_KEY", "YOUR_DEFAULT_KEY") api_key = os.getenv("FOOTBALL_DATA_API_KEY", "YOUR_DEFAULT_KEY")
team_name = args.get("team") team_name = args.get("team")
month = args.get("month") start_date_str = args.get("start_date")
headers = {'X-Auth-Token': api_key} end_date_str = args.get("end_date")
headers = {"X-Auth-Token": api_key}
team_name = team_name.lower() team_name = team_name.lower()
month = month.capitalize()
try: try:
month_number = datetime.strptime(month, "%B").month start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
end_date = datetime.strptime(end_date_str, "%Y-%m-%d")
except ValueError: except ValueError:
return {"error": "Invalid month provided."} return {
"error": "Invalid date provided. Expected format YYYY-MM-DD for both start_date and end_date."
}
# Fetch team ID # Fetch team ID
teams_response = requests.get(f'{BASE_URL}/competitions/PL/teams', headers=headers) teams_response = requests.get(f"{BASE_URL}/competitions/PL/teams", headers=headers)
if teams_response.status_code != 200: if teams_response.status_code != 200:
return {"error": "Failed to fetch teams data."} return {"error": "Failed to fetch teams data."}
teams_data = teams_response.json() teams_data = teams_response.json()
team_id = None team_id = None
for team in teams_data['teams']: for team in teams_data["teams"]:
if team_name in team['name'].lower(): if team_name in team["name"].lower():
team_id = team['id'] team_id = team["id"]
break break
if not team_id: if not team_id:
return {"error": "Team not found."} return {"error": "Team not found."}
# Fetch fixtures start_date_formatted = start_date.strftime("%Y-%m-%d")
match_date_from = f'2025-{month_number:02}-01' end_date_formatted = end_date.strftime("%Y-%m-%d")
match_date_to = f'2025-{month_number:02}-31' fixtures_url = f"{BASE_URL}/teams/{team_id}/matches?dateFrom={start_date_formatted}&dateTo={end_date_formatted}"
print(f'{BASE_URL}/teams/{team_id}/matches?dateFrom={match_date_from}&dateTo={match_date_to}') print(fixtures_url)
fixtures_response = requests.get(f'{BASE_URL}/teams/{team_id}/matches?dateFrom={match_date_from}&dateTo={match_date_to}', headers=headers)
fixtures_response = requests.get(fixtures_url, headers=headers)
if fixtures_response.status_code != 200: if fixtures_response.status_code != 200:
return {"error": "Failed to fetch fixtures data."} return {"error": "Failed to fetch fixtures data."}
fixtures_data = fixtures_response.json() fixtures_data = fixtures_response.json()
matching_fixtures = [] matching_fixtures = []
for match in fixtures_data['matches']: for match in fixtures_data.get("matches", []):
print(match) match_datetime = datetime.strptime(match["utcDate"], "%Y-%m-%dT%H:%M:%SZ")
match_date = datetime.strptime(match['utcDate'], "%Y-%m-%dT%H:%M:%SZ") if match["competition"]["code"] == "PL":
if match['competition']['code'] == 'PL': matching_fixtures.append(
matching_fixtures.append({ {
"date": match_date.strftime("%Y-%m-%d"), "date": match_datetime.strftime("%Y-%m-%d"),
"homeTeam": match['homeTeam']['name'], "homeTeam": match["homeTeam"]["name"],
"awayTeam": match['awayTeam']['name'], "awayTeam": match["awayTeam"]["name"],
}) }
)
return {"fixtures": matching_fixtures} return {"fixtures": matching_fixtures}

View File

@@ -44,12 +44,12 @@ search_trains_tool = ToolDefinition(
ToolArgument( ToolArgument(
name="outbound_time", name="outbound_time",
type="ISO8601", type="ISO8601",
description="The date and time to search for outbound trains", description="The date and time to search for outbound trains. If time of day isn't asked for, assume a decent time of day/evening for the outbound journey",
), ),
ToolArgument( ToolArgument(
name="return_time", name="return_time",
type="ISO8601", type="ISO8601",
description="The date and time to search for return trains", description="The date and time to search for return trains. If time of day isn't asked for, assume a decent time of day/evening for the inbound journey",
), ),
], ],
) )
@@ -85,7 +85,7 @@ create_invoice_tool = ToolDefinition(
search_fixtures_tool = ToolDefinition( search_fixtures_tool = ToolDefinition(
name="SearchFixtures", name="SearchFixtures",
description="Search for upcoming fixtures for a given team and month. Valid teams this 24/25 season are Arsenal FC, Aston Villa FC, AFC Bournemouth, Brentford FC, Brighton & Hove Albion FC, Chelsea FC, Crystal Palace FC, Everton FC, Fulham FC, Ipswich Town FC, Leicester City FC, Liverpool FC, Manchester City FC, Manchester United FC, Newcastle United FC, Nottingham Forest FC, Southampton FC, Tottenham Hotspur FC, West Ham United FC, Wolverhampton Wanderers FC", description="Search for upcoming fixtures for a given team within a specified date range. Valid teams this 24/25 season are Arsenal FC, Aston Villa FC, AFC Bournemouth, Brentford FC, Brighton & Hove Albion FC, Chelsea FC, Crystal Palace FC, Everton FC, Fulham FC, Ipswich Town FC, Leicester City FC, Liverpool FC, Manchester City FC, Manchester United FC, Newcastle United FC, Nottingham Forest FC, Southampton FC, Tottenham Hotspur FC, West Ham United FC, Wolverhampton Wanderers FC",
arguments=[ arguments=[
ToolArgument( ToolArgument(
name="team", name="team",
@@ -93,9 +93,14 @@ search_fixtures_tool = ToolDefinition(
description="The full name of the team to search for.", description="The full name of the team to search for.",
), ),
ToolArgument( ToolArgument(
name="month", name="start_date",
type="string", type="string",
description="The month to search for fixtures.", description="The start date (YYYY-MM-DD) for the fixture search.",
),
ToolArgument(
name="end_date",
type="string",
description="The end date (YYYY-MM-DD) for the fixture search.",
), ),
], ],
) )

View File

@@ -78,7 +78,7 @@ class ToolWorkflow:
f"### The '{current_tool}' tool completed successfully with {dynamic_result}. " f"### The '{current_tool}' tool completed successfully with {dynamic_result}. "
"INSTRUCTIONS: Parse this tool result as plain text, and use the system prompt containing the list of tools in sequence and the conversation history (and previous tool_results) to figure out next steps, if any. " "INSTRUCTIONS: Parse this tool result as plain text, and use the system prompt containing the list of tools in sequence and the conversation history (and previous tool_results) to figure out next steps, if any. "
"You will need to use the tool_results to auto-fill arguments for subsequent tools and also to figure out if all tools have been run." "You will need to use the tool_results to auto-fill arguments for subsequent tools and also to figure out if all tools have been run."
'{"next": "<question|confirm|done>", "tool": "<tool_name or null>", "args": {"<arg1>": "<value1 or null>", "<arg2>": "<value2 or null>}, "response": "<plain text>"}' '{"next": "<question|confirm|done>", "tool": "<tool_name or null>", "args": {"<arg1>": "<value1 or null>", "<arg2>": "<value2 or null>}, "response": "<plain text (can include \\n line breaks)>"}'
"ONLY return those json keys (next, tool, args, response), nothing else." "ONLY return those json keys (next, tool, args, response), nothing else."
'Next should only be "done" if all tools have been run (use the system prompt to figure that out).' 'Next should only be "done" if all tools have been run (use the system prompt to figure that out).'
'Next should be "question" if the tool is not the last one in the sequence.' 'Next should be "question" if the tool is not the last one in the sequence.'