feat: add path parameter validation for source_id (#5524)

🤖 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:39:35 -07:00
committed by Caren Thomas
parent 2878a6e4bd
commit 3ac7cde434
3 changed files with 72 additions and 18 deletions

View File

@@ -1704,8 +1704,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
}
],
"responses": {
@@ -1744,8 +1750,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
}
],
"requestBody": {
@@ -1794,8 +1806,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
}
],
"responses": {
@@ -1996,8 +2014,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
},
{
"name": "duplicate_handling",
@@ -2077,8 +2101,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
}
],
"responses": {
@@ -2123,8 +2153,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
},
{
"name": "after",
@@ -2217,8 +2253,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
},
{
"name": "limit",
@@ -4527,8 +4569,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
},
{
"name": "agent_id",
@@ -4645,8 +4693,14 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^source-[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 source in the format 'source-<uuid4>'",
"examples": ["source-123e4567-e89b-42d3-8456-426614174000"],
"title": "Source Id"
}
},
"description": "The ID of the source in the format 'source-<uuid4>'"
},
{
"name": "agent_id",

View File

@@ -485,7 +485,7 @@ async def modify_approval(
@router.patch("/{agent_id}/sources/attach/{source_id}", response_model=AgentState, operation_id="attach_source_to_agent")
async def attach_source(
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
agent_id: str = PATH_VALIDATORS["agent"],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -539,7 +539,7 @@ async def attach_folder_to_agent(
@router.patch("/{agent_id}/sources/detach/{source_id}", response_model=AgentState, operation_id="detach_source_from_agent")
async def detach_source(
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
agent_id: str = PATH_VALIDATORS["agent"],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),

View File

@@ -60,7 +60,7 @@ async def count_sources(
@router.get("/{source_id}", response_model=Source, operation_id="retrieve_source", deprecated=True)
async def retrieve_source(
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -157,8 +157,8 @@ async def create_source(
@router.patch("/{source_id}", response_model=Source, operation_id="modify_source", deprecated=True)
async def modify_source(
source_id: str,
source: SourceUpdate,
source_id: str = PATH_VALIDATORS["source"],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -173,7 +173,7 @@ async def modify_source(
@router.delete("/{source_id}", response_model=None, operation_id="delete_source", deprecated=True)
async def delete_source(
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -209,7 +209,7 @@ async def delete_source(
@router.post("/{source_id}/upload", response_model=FileMetadata, operation_id="upload_file_to_source", deprecated=True)
async def upload_file_to_source(
file: UploadFile,
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
duplicate_handling: DuplicateFileHandling = Query(DuplicateFileHandling.SUFFIX, description="How to handle duplicate filenames"),
name: Optional[str] = Query(None, description="Optional custom name to override the uploaded file's name"),
server: "SyncServer" = Depends(get_letta_server),
@@ -324,7 +324,7 @@ async def upload_file_to_source(
@router.get("/{source_id}/agents", response_model=List[str], operation_id="get_agents_for_source", deprecated=True)
async def get_agents_for_source(
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -337,7 +337,7 @@ async def get_agents_for_source(
@router.get("/{source_id}/passages", response_model=List[Passage], operation_id="list_source_passages", deprecated=True)
async def list_source_passages(
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
after: Optional[str] = Query(None, description="Message after which to retrieve the returned messages."),
before: Optional[str] = Query(None, description="Message before which to retrieve the returned messages."),
limit: int = Query(100, description="Maximum number of messages to retrieve."),
@@ -359,7 +359,7 @@ async def list_source_passages(
@router.get("/{source_id}/files", response_model=List[FileMetadata], operation_id="list_source_files", deprecated=True)
async def list_source_files(
source_id: str,
source_id: str = PATH_VALIDATORS["source"],
limit: int = Query(1000, description="Number of files to return"),
after: Optional[str] = Query(None, description="Pagination cursor to fetch the next set of results"),
include_content: bool = Query(False, description="Whether to include full file content"),