Skip to content

Commit 90c8c6e

Browse files
bensynapseclaude
andcommitted
fix(crewai-tools): address review — drop utr listing, numeric player_id, tour enum, docs
- Remove 'utr' from the rankings systems: the API's /rankings listing mode does not serve it (utr is a rating, not a ranking). - Type player_id as int to match the API's integer path parameter and avoid pydantic v2's refusal to coerce int input to a str field. - Constrain tour to the API's enum (atp, wta, challenger, itf, juniors). - Document tour/limit/offset in both the package README and the docs page; note the rankings action's PRO-plan requirement in the schema. - Add docstrings and tests for the new validation behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a9bc259 commit 90c8c6e

5 files changed

Lines changed: 124 additions & 50 deletions

File tree

docs/edge/en/tools/search-research/livetennistool.mdx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,18 @@ LIVETENNIS_API_KEY=your_api_key # Free key at livetennisapi.com
2424
| `action` | What it returns | Plan |
2525
|---|---|---|
2626
| `live_matches` | Matches in play with current scores (optional `tour` filter) | Free |
27-
| `upcoming_matches` | Matches starting soon | Free |
28-
| `fixtures` | Scheduled matches | Free |
27+
| `upcoming_matches` | Matches starting soon (optional `tour` filter) | Free |
28+
| `fixtures` | Scheduled matches (optional `tour` filter) | Free |
2929
| `search_players` | Player search by name (requires `search`) | Free |
30-
| `player_profile` | Single player detail, including current ranking (requires `player_id`) | Free |
31-
| `rankings` | Published ranking table (requires `system`: `atp`, `wta`, `itf_jt`, `itf_mt`, `itf_wt`, `utr`) | PRO |
30+
| `player_profile` | Single player detail, including current ranking (requires `player_id`, the numeric id from `search_players`) | Free |
31+
| `rankings` | Published ranking table (requires `system`: `atp`, `wta`, `itf_jt`, `itf_mt`, `itf_wt`; UTR has no listing — it is a rating, not a ranking) | PRO |
3232
| `usage` | Your API quota vs. consumption | Free |
3333

34+
### Parameters
35+
36+
- `tour` — optional filter for `live_matches`, `upcoming_matches` and `fixtures`: one of `atp`, `wta`, `challenger`, `itf`, `juniors`. Omit for all tours.
37+
- `limit` / `offset` — pagination for the list actions (`live_matches`, `upcoming_matches`, `fixtures`, `search_players`, `rankings`). The API default is 50 results.
38+
3439
## Basic Usage
3540

3641
```python
@@ -59,7 +64,7 @@ print(tool.run(action="live_matches", tour="atp"))
5964

6065
# Find a player, then load their profile
6166
players = tool.run(action="search_players", search="alcaraz")
62-
profile = tool.run(action="player_profile", player_id="<id from search>")
67+
profile = tool.run(action="player_profile", player_id=12345) # numeric id from the search result
6368
```
6469

6570
## Error Handling

lib/crewai-tools/src/crewai_tools/tools/live_tennis_tool/README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@ The tool is scoped to REST endpoints, most of which are available on the free ti
88

99
| `action` | Endpoint | Plan | Notes |
1010
|---|---|---|---|
11-
| `live_matches` | `GET /matches?status=live` | Free | Matches in play with current scores |
12-
| `upcoming_matches` | `GET /matches?status=upcoming` | Free | Matches starting soon |
13-
| `fixtures` | `GET /fixtures` | Free | Scheduled matches |
11+
| `live_matches` | `GET /matches?status=live` | Free | Matches in play with current scores; optional `tour` |
12+
| `upcoming_matches` | `GET /matches?status=upcoming` | Free | Matches starting soon; optional `tour` |
13+
| `fixtures` | `GET /fixtures` | Free | Scheduled matches; optional `tour` |
1414
| `search_players` | `GET /players?search=` | Free | Requires `search` |
15-
| `player_profile` | `GET /players/{id}` | Free | Requires `player_id`; includes current ranking |
16-
| `rankings` | `GET /rankings?system=` | PRO | Requires `system` (`atp`, `wta`, `itf_jt`, `itf_mt`, `itf_wt`, `utr`) |
15+
| `player_profile` | `GET /players/{id}` | Free | Requires `player_id` (numeric id from `search_players`); includes current ranking |
16+
| `rankings` | `GET /rankings?system=` | PRO | Requires `system` (`atp`, `wta`, `itf_jt`, `itf_mt`, `itf_wt`); UTR has no listing (it is a rating, not a ranking) |
1717
| `usage` | `GET /usage` | Free | Your quota vs. consumption; exempt from quota |
1818

19+
### Parameters
20+
21+
- `tour` — optional filter for `live_matches`, `upcoming_matches` and `fixtures`: one of `atp`, `wta`, `challenger`, `itf`, `juniors`. Omit for all tours.
22+
- `limit` / `offset` — pagination for the list actions (`live_matches`, `upcoming_matches`, `fixtures`, `search_players`, `rankings`). The API default is 50 results.
23+
1924
The free tier is keyed and rate-limited to 30 requests/minute and 100 requests/day. Completed-match history is a paid feature and is not part of this tool. The API also offers a WebSocket push feed and model win probability on its top tier; this tool intentionally sticks to the polling REST surface.
2025

2126
## Environment Variables
@@ -38,7 +43,7 @@ print(tool.run(action="live_matches", tour="atp"))
3843

3944
# Find a player, then load their profile
4045
players = tool.run(action="search_players", search="alcaraz")
41-
profile = tool.run(action="player_profile", player_id="<id from search>")
46+
profile = tool.run(action="player_profile", player_id=12345) # numeric id from the search result
4247
```
4348

4449
## With an Agent

lib/crewai-tools/src/crewai_tools/tools/live_tennis_tool/live_tennis_tool.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import json
66
import os
77
from typing import Any
8-
from urllib.parse import quote
98

109
from crewai.tools import BaseTool, EnvVar
1110
from pydantic import BaseModel, Field, ValidationError
@@ -48,6 +47,12 @@ class LiveTennisTool(BaseTool):
4847
)
4948

5049
def _run(self, **kwargs: Any) -> str:
50+
"""Validate the arguments, call the API, and return the response.
51+
52+
Returns the endpoint's JSON as a string on success, or a readable
53+
error message (missing key, invalid arguments, 401/403/429/other
54+
HTTP errors, network failure) so an agent can recover.
55+
"""
5156
api_key = os.environ.get(API_KEY_ENV_VAR, "").strip()
5257
if not api_key:
5358
return (
@@ -116,7 +121,7 @@ def _build_request(params: LiveTennisToolSchema) -> tuple[str, dict[str, Any]]:
116121
query["search"] = params.search
117122
return "/players", query
118123
if params.action == "player_profile":
119-
return f"/players/{quote(str(params.player_id), safe='')}", {}
124+
return f"/players/{params.player_id}", {}
120125
if params.action == "rankings":
121126
query["system"] = params.system
122127
return "/rankings", query

lib/crewai-tools/src/crewai_tools/tools/live_tennis_tool/schemas.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,17 @@
1616
"rankings",
1717
"usage",
1818
]
19+
"""Operations the tool can perform, each mapping to one REST endpoint."""
1920

20-
RankingSystem = Literal["atp", "wta", "itf_jt", "itf_mt", "itf_wt", "utr"]
21+
RankingSystem = Literal["atp", "wta", "itf_jt", "itf_mt", "itf_wt"]
22+
"""Ranking systems with a published rank-ordered listing.
23+
24+
UTR is intentionally absent: the API's ``/rankings`` listing mode does not
25+
serve it ("`utr` has no listing — it is a rating, not a ranking").
26+
"""
27+
28+
Tour = Literal["atp", "wta", "challenger", "itf", "juniors"]
29+
"""Valid ``tour`` filter values; an unrecognised value is a 400 from the API."""
2130

2231

2332
class LiveTennisToolSchema(BaseModel):
@@ -31,14 +40,15 @@ class LiveTennisToolSchema(BaseModel):
3140
"'fixtures' (scheduled matches), 'search_players' (find players by "
3241
"name, requires 'search'), 'player_profile' (single player detail "
3342
"including current ranking, requires 'player_id'), 'rankings' "
34-
"(published ranking table, requires 'system'), 'usage' (your API "
35-
"quota and consumption)."
43+
"(published ranking table, requires 'system'; needs a PRO-plan "
44+
"API key), 'usage' (your API quota and consumption)."
3645
),
3746
)
38-
tour: str | None = Field(
47+
tour: Tour | None = Field(
3948
default=None,
4049
description=(
41-
"Optional tour filter for match and fixture actions, e.g. 'atp' or 'wta'."
50+
"Optional tour filter for match and fixture actions: 'atp', 'wta', "
51+
"'challenger', 'itf' or 'juniors'. Omit for all tours."
4252
),
4353
)
4454
search: str | None = Field(
@@ -48,18 +58,18 @@ class LiveTennisToolSchema(BaseModel):
4858
"'search_players' action."
4959
),
5060
)
51-
player_id: str | None = Field(
61+
player_id: int | None = Field(
5262
default=None,
5363
description=(
54-
"Player id as returned by 'search_players'. Required for the "
55-
"'player_profile' action."
64+
"Numeric player id as returned by 'search_players'. Required for "
65+
"the 'player_profile' action."
5666
),
5767
)
5868
system: RankingSystem | None = Field(
5969
default=None,
6070
description=(
6171
"Ranking system for the 'rankings' action: 'atp', 'wta', 'itf_jt', "
62-
"'itf_mt', 'itf_wt' or 'utr'."
72+
"'itf_mt' or 'itf_wt'. The rankings listing needs a PRO-plan key."
6373
),
6474
)
6575
limit: int | None = Field(
@@ -75,13 +85,12 @@ class LiveTennisToolSchema(BaseModel):
7585

7686
@model_validator(mode="after")
7787
def _validate_action_arguments(self) -> LiveTennisToolSchema:
88+
"""Ensure the arguments each action depends on are present."""
7889
if self.action == "search_players" and not (
7990
self.search and self.search.strip()
8091
):
8192
raise ValueError("'search' is required for the 'search_players' action.")
82-
if self.action == "player_profile" and not (
83-
self.player_id and self.player_id.strip()
84-
):
93+
if self.action == "player_profile" and self.player_id is None:
8594
raise ValueError("'player_id' is required for the 'player_profile' action.")
8695
if self.action == "rankings" and self.system is None:
8796
raise ValueError("'system' is required for the 'rankings' action.")

0 commit comments

Comments
 (0)