feat: add path parameter validation for tool_id (#5525)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Kian Jones
2025-10-17 16:37:16 -07:00
committed by Caren Thomas
parent c4379c3b8b
commit f04bc0753c
3 changed files with 41 additions and 10 deletions

View File

@@ -269,8 +269,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 41,
"maxLength": 41,
"pattern": "^tool-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"description": "The ID of the tool in the format 'tool-<uuid4>'",
"examples": ["tool-123e4567-e89b-42d3-8456-426614174000"],
"title": "Tool Id"
}
},
"description": "The ID of the tool in the format 'tool-<uuid4>'"
}
],
"responses": {
@@ -306,8 +312,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 41,
"maxLength": 41,
"pattern": "^tool-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"description": "The ID of the tool in the format 'tool-<uuid4>'",
"examples": ["tool-123e4567-e89b-42d3-8456-426614174000"],
"title": "Tool Id"
}
},
"description": "The ID of the tool in the format 'tool-<uuid4>'"
}
],
"responses": {
@@ -345,8 +357,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 41,
"maxLength": 41,
"pattern": "^tool-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"description": "The ID of the tool in the format 'tool-<uuid4>'",
"examples": ["tool-123e4567-e89b-42d3-8456-426614174000"],
"title": "Tool Id"
}
},
"description": "The ID of the tool in the format 'tool-<uuid4>'"
}
],
"requestBody": {
@@ -4242,8 +4260,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 41,
"maxLength": 41,
"pattern": "^tool-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"description": "The ID of the tool in the format 'tool-<uuid4>'",
"examples": ["tool-123e4567-e89b-42d3-8456-426614174000"],
"title": "Tool Id"
}
},
"description": "The ID of the tool in the format 'tool-<uuid4>'"
},
{
"name": "agent_id",
@@ -4298,8 +4322,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 41,
"maxLength": 41,
"pattern": "^tool-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"description": "The ID of the tool in the format 'tool-<uuid4>'",
"examples": ["tool-123e4567-e89b-42d3-8456-426614174000"],
"title": "Tool Id"
}
},
"description": "The ID of the tool in the format 'tool-<uuid4>'"
},
{
"name": "agent_id",

View File

@@ -434,7 +434,7 @@ async def list_agent_tools(
@router.patch("/{agent_id}/tools/attach/{tool_id}", response_model=AgentState, operation_id="attach_tool")
async def attach_tool(
tool_id: str,
tool_id: str = PATH_VALIDATORS["tool"],
agent_id: str = PATH_VALIDATORS["agent"],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -450,7 +450,7 @@ async def attach_tool(
@router.patch("/{agent_id}/tools/detach/{tool_id}", response_model=AgentState, operation_id="detach_tool")
async def detach_tool(
tool_id: str,
tool_id: str = PATH_VALIDATORS["tool"],
agent_id: str = PATH_VALIDATORS["agent"],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),

View File

@@ -38,6 +38,7 @@ from letta.services.mcp.oauth_utils import MCPOAuthSession, drill_down_exception
from letta.services.mcp.stdio_client import AsyncStdioMCPClient
from letta.services.mcp.types import OauthStreamEvent
from letta.settings import tool_settings
from letta.validators import PATH_VALIDATORS
router = APIRouter(prefix="/tools", tags=["tools"])
@@ -46,7 +47,7 @@ logger = get_logger(__name__)
@router.delete("/{tool_id}", operation_id="delete_tool")
async def delete_tool(
tool_id: str,
tool_id: str = PATH_VALIDATORS["tool"],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -149,7 +150,7 @@ async def count_tools(
@router.get("/{tool_id}", response_model=Tool, operation_id="retrieve_tool")
async def retrieve_tool(
tool_id: str,
tool_id: str = PATH_VALIDATORS["tool"],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -297,8 +298,8 @@ async def upsert_tool(
@router.patch("/{tool_id}", response_model=Tool, operation_id="modify_tool")
async def modify_tool(
tool_id: str,
request: ToolUpdate = Body(...),
tool_id: str = PATH_VALIDATORS["tool"],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):