fix: source id from pydantic base class rather than expected string id (#5554)

* first pass

* hacky fix bc of path import
This commit is contained in:
Kian Jones
2025-10-17 19:21:48 -07:00
committed by Caren Thomas
parent de7011e4de
commit 448ba33c70
14 changed files with 193 additions and 219 deletions

View File

@@ -2521,14 +2521,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
}
],
"responses": {
@@ -2566,14 +2561,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
}
],
"requestBody": {
@@ -2621,14 +2611,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
}
],
"responses": {
@@ -2925,14 +2910,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
},
{
"name": "duplicate_handling",
@@ -3011,14 +2991,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
},
{
"name": "before",
@@ -3143,14 +3118,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
},
{
"name": "before",
@@ -3275,14 +3245,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
},
{
"name": "before",
@@ -3419,14 +3384,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"pattern": "^source-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
"title": "Folder Id"
},
"description": "The ID of the folder in the format 'folder-<uuid4>'"
}
},
{
"name": "file_id",
@@ -3434,14 +3394,9 @@
"required": true,
"schema": {
"type": "string",
"minLength": 41,
"maxLength": 41,
"pattern": "^file-[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 file in the format 'file-<uuid4>'",
"examples": ["file-123e4567-e89b-42d3-8456-426614174000"],
"title": "File Id"
},
"description": "The ID of the file in the format 'file-<uuid4>'"
}
}
],
"responses": {
@@ -4626,19 +4581,19 @@
"operationId": "attach_folder_to_agent",
"parameters": [
{
"name": "folder_id",
"name": "source_id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"title": "Folder Id"
"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 folder in the format 'folder-<uuid4>'"
"description": "The ID of the source in the format 'source-<uuid4>'"
},
{
"name": "agent_id",
@@ -4750,19 +4705,19 @@
"operationId": "detach_folder_from_agent",
"parameters": [
{
"name": "folder_id",
"name": "source_id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^folder-[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 folder in the format 'folder-<uuid4>'",
"examples": ["folder-123e4567-e89b-42d3-8456-426614174000"],
"title": "Folder Id"
"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 folder in the format 'folder-<uuid4>'"
"description": "The ID of the source in the format 'source-<uuid4>'"
},
{
"name": "agent_id",

View File

@@ -30,9 +30,9 @@ from letta.otel.context import get_ctx_attributes
from letta.otel.metric_registry import MetricRegistry
from letta.schemas.agent import AgentState, CreateAgent, UpdateAgent
from letta.schemas.agent_file import AgentFileSchema
from letta.schemas.block import Block, BlockUpdate
from letta.schemas.block import BaseBlock, Block, BlockUpdate
from letta.schemas.enums import AgentType, RunStatus
from letta.schemas.file import AgentFileAttachment, PaginatedAgentFiles
from letta.schemas.file import AgentFileAttachment, FileMetadataBase, PaginatedAgentFiles
from letta.schemas.group import Group
from letta.schemas.job import LettaRequestConfig
from letta.schemas.letta_message import LettaMessageUnion, LettaMessageUpdateUnion, MessageType
@@ -46,11 +46,11 @@ from letta.schemas.memory import (
CreateArchivalMemory,
Memory,
)
from letta.schemas.message import MessageCreate, MessageCreateType, MessageSearchRequest, MessageSearchResult
from letta.schemas.message import BaseMessage, MessageCreate, MessageCreateType, MessageSearchRequest, MessageSearchResult
from letta.schemas.passage import Passage
from letta.schemas.run import Run as PydanticRun, RunUpdate
from letta.schemas.source import Source
from letta.schemas.tool import Tool
from letta.schemas.source import BaseSource, Source
from letta.schemas.tool import BaseTool, Tool
from letta.schemas.user import User
from letta.serialize_schemas.pydantic_agent_schema import AgentSchema
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
@@ -170,7 +170,7 @@ class IndentedORJSONResponse(Response):
@router.get("/{agent_id}/export", response_class=IndentedORJSONResponse, operation_id="export_agent")
async def export_agent(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
max_steps: int = 100,
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -353,7 +353,7 @@ async def import_agent(
@router.get("/{agent_id}/context", response_model=ContextWindowOverview, operation_id="retrieve_agent_context_window")
async def retrieve_agent_context_window(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -393,7 +393,7 @@ async def create_agent(
@router.patch("/{agent_id}", response_model=AgentState, operation_id="modify_agent")
async def modify_agent(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
update_agent: UpdateAgent = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -405,7 +405,7 @@ async def modify_agent(
@router.get("/{agent_id}/tools", response_model=list[Tool], operation_id="list_agent_tools")
async def list_agent_tools(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
before: Optional[str] = Query(
@@ -434,8 +434,8 @@ 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 = PATH_VALIDATORS["tool"],
agent_id: str = PATH_VALIDATORS["agent"],
tool_id: str = PATH_VALIDATORS[BaseTool.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -450,8 +450,8 @@ 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 = PATH_VALIDATORS["tool"],
agent_id: str = PATH_VALIDATORS["agent"],
tool_id: str = PATH_VALIDATORS[BaseTool.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -468,7 +468,7 @@ async def detach_tool(
async def modify_approval(
tool_name: str,
requires_approval: bool,
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -485,8 +485,8 @@ 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 = PATH_VALIDATORS["source"],
agent_id: str = PATH_VALIDATORS["agent"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -512,8 +512,8 @@ async def attach_source(
@router.patch("/{agent_id}/folders/attach/{folder_id}", response_model=AgentState, operation_id="attach_folder_to_agent")
async def attach_folder_to_agent(
folder_id: str = PATH_VALIDATORS["folder"],
agent_id: str = PATH_VALIDATORS["agent"],
folder_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -539,8 +539,8 @@ 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 = PATH_VALIDATORS["source"],
agent_id: str = PATH_VALIDATORS["agent"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -569,8 +569,8 @@ async def detach_source(
@router.patch("/{agent_id}/folders/detach/{folder_id}", response_model=AgentState, operation_id="detach_folder_from_agent")
async def detach_folder_from_agent(
folder_id: str = PATH_VALIDATORS["folder"],
agent_id: str = PATH_VALIDATORS["agent"],
folder_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -599,7 +599,7 @@ async def detach_folder_from_agent(
@router.patch("/{agent_id}/files/close-all", response_model=List[str], operation_id="close_all_open_files")
async def close_all_open_files(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -616,8 +616,8 @@ async def close_all_open_files(
@router.patch("/{agent_id}/files/{file_id}/open", response_model=List[str], operation_id="open_file")
async def open_file(
file_id: str = PATH_VALIDATORS["file"],
agent_id: str = PATH_VALIDATORS["agent"],
file_id: str = PATH_VALIDATORS[FileMetadataBase.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -665,8 +665,8 @@ async def open_file(
@router.patch("/{agent_id}/files/{file_id}/close", response_model=None, operation_id="close_file")
async def close_file(
file_id: str = PATH_VALIDATORS["file"],
agent_id: str = PATH_VALIDATORS["agent"],
file_id: str = PATH_VALIDATORS[FileMetadataBase.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -690,7 +690,7 @@ async def close_file(
@router.get("/{agent_id}", response_model=AgentState, operation_id="retrieve_agent")
async def retrieve_agent(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
include_relationships: list[str] | None = Query(
None,
description=(
@@ -713,7 +713,7 @@ async def retrieve_agent(
@router.delete("/{agent_id}", response_model=None, operation_id="delete_agent")
async def delete_agent(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -727,7 +727,7 @@ async def delete_agent(
@router.get("/{agent_id}/sources", response_model=list[Source], operation_id="list_agent_sources")
async def list_agent_sources(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
before: Optional[str] = Query(
@@ -758,7 +758,7 @@ async def list_agent_sources(
@router.get("/{agent_id}/folders", response_model=list[Source], operation_id="list_agent_folders")
async def list_agent_folders(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
before: Optional[str] = Query(
@@ -789,7 +789,7 @@ async def list_agent_folders(
@router.get("/{agent_id}/files", response_model=PaginatedAgentFiles, operation_id="list_agent_files")
async def list_agent_files(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
before: Optional[str] = Query(
None, description="File ID cursor for pagination. Returns files that come before this file ID in the specified sort order"
),
@@ -854,7 +854,7 @@ async def list_agent_files(
# TODO: remove? can also get with agent blocks
@router.get("/{agent_id}/core-memory", response_model=Memory, operation_id="retrieve_agent_memory")
async def retrieve_agent_memory(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -870,7 +870,7 @@ async def retrieve_agent_memory(
@router.get("/{agent_id}/core-memory/blocks/{block_label}", response_model=Block, operation_id="retrieve_core_memory_block")
async def retrieve_block(
block_label: str,
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -884,7 +884,7 @@ async def retrieve_block(
@router.get("/{agent_id}/core-memory/blocks", response_model=list[Block], operation_id="list_core_memory_blocks")
async def list_blocks(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
before: Optional[str] = Query(
@@ -917,7 +917,7 @@ async def list_blocks(
@router.patch("/{agent_id}/core-memory/blocks/{block_label}", response_model=Block, operation_id="modify_core_memory_block")
async def modify_block(
block_label: str,
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
block_update: BlockUpdate = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -939,8 +939,8 @@ async def modify_block(
@router.patch("/{agent_id}/core-memory/blocks/attach/{block_id}", response_model=AgentState, operation_id="attach_core_memory_block")
async def attach_block(
block_id: str = PATH_VALIDATORS["block"],
agent_id: str = PATH_VALIDATORS["agent"],
block_id: str = PATH_VALIDATORS[BaseBlock.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -953,8 +953,8 @@ async def attach_block(
@router.patch("/{agent_id}/core-memory/blocks/detach/{block_id}", response_model=AgentState, operation_id="detach_core_memory_block")
async def detach_block(
block_id: str = PATH_VALIDATORS["block"],
agent_id: str = PATH_VALIDATORS["agent"],
block_id: str = PATH_VALIDATORS[BaseBlock.__id_prefix__],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -967,7 +967,7 @@ async def detach_block(
@router.get("/{agent_id}/archival-memory", response_model=list[Passage], operation_id="list_passages")
async def list_passages(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
after: str | None = Query(None, description="Unique ID of the memory to start the query range at."),
before: str | None = Query(None, description="Unique ID of the memory to end the query range at."),
@@ -996,7 +996,7 @@ async def list_passages(
@router.post("/{agent_id}/archival-memory", response_model=list[Passage], operation_id="create_passage")
async def create_passage(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
request: CreateArchivalMemory = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -1013,7 +1013,7 @@ async def create_passage(
@router.get("/{agent_id}/archival-memory/search", response_model=ArchivalMemorySearchResponse, operation_id="search_archival_memory")
async def search_archival_memory(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
query: str = Query(..., description="String to search for using semantic similarity"),
tags: Optional[List[str]] = Query(None, description="Optional list of tags to filter search results"),
tag_match_mode: Literal["any", "all"] = Query(
@@ -1061,7 +1061,7 @@ async def search_archival_memory(
@router.delete("/{agent_id}/archival-memory/{memory_id}", response_model=None, operation_id="delete_passage")
async def delete_passage(
memory_id: str,
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
# memory_id: str = Query(..., description="Unique ID of the memory to be deleted."),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -1082,7 +1082,7 @@ AgentMessagesResponse = Annotated[
@router.get("/{agent_id}/messages", response_model=AgentMessagesResponse, operation_id="list_messages")
async def list_messages(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
before: Optional[str] = Query(
None, description="Message ID cursor for pagination. Returns messages that come before this message ID in the specified sort order"
@@ -1127,8 +1127,8 @@ async def list_messages(
@router.patch("/{agent_id}/messages/{message_id}", response_model=LettaMessageUnion, operation_id="modify_message")
async def modify_message(
agent_id: str = PATH_VALIDATORS["agent"], # backwards compatible. Consider removing for v1
message_id: str = PATH_VALIDATORS["message"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__], # backwards compatible. Consider removing for v1
message_id: str = PATH_VALIDATORS[BaseMessage.__id_prefix__],
request: LettaMessageUpdateUnion = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -1151,7 +1151,7 @@ async def modify_message(
)
async def send_message(
request_obj: Request, # FastAPI Request
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
request: LettaRequest = Body(...),
headers: HeaderParams = Depends(get_headers),
@@ -1278,7 +1278,7 @@ async def send_message(
)
async def send_message_streaming(
request_obj: Request, # FastAPI Request
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
request: LettaStreamingRequest = Body(...),
headers: HeaderParams = Depends(get_headers),
@@ -1311,7 +1311,7 @@ class CancelAgentRunRequest(BaseModel):
@router.post("/{agent_id}/messages/cancel", operation_id="cancel_agent_run")
async def cancel_agent_run(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
request: CancelAgentRunRequest = Body(None),
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -1487,7 +1487,7 @@ async def _process_message_background(
operation_id="create_agent_message_async",
)
async def send_message_async(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
request: LettaAsyncRequest = Body(...),
headers: HeaderParams = Depends(get_headers),
@@ -1591,7 +1591,7 @@ async def send_message_async(
@router.patch("/{agent_id}/reset-messages", response_model=AgentState, operation_id="reset_messages")
async def reset_messages(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
add_default_initial_messages: bool = Query(default=False, description="If true, adds the default initial messages after resetting."),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -1605,7 +1605,7 @@ async def reset_messages(
@router.get("/{agent_id}/groups", response_model=list[Group], operation_id="list_agent_groups")
async def list_agent_groups(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
manager_type: str | None = Query(None, description="Manager type to filter groups by"),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -1641,7 +1641,7 @@ async def list_agent_groups(
operation_id="preview_raw_payload",
)
async def preview_raw_payload(
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
request: Union[LettaRequest, LettaStreamingRequest] = Body(...),
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -1687,7 +1687,7 @@ async def preview_raw_payload(
@router.post("/{agent_id}/summarize", status_code=204, operation_id="summarize_agent_conversation")
async def summarize_agent_conversation(
request_obj: Request, # FastAPI Request
agent_id: str = PATH_VALIDATORS["agent"],
agent_id: str = PATH_VALIDATORS[AgentState.__id_prefix__],
max_message_length: int = Query(..., description="Maximum number of messages to retain after summarization."),
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),

View File

@@ -3,7 +3,7 @@ from typing import List, Literal, Optional
from fastapi import APIRouter, Body, Depends, Query
from pydantic import BaseModel
from letta.schemas.archive import Archive as PydanticArchive
from letta.schemas.archive import Archive as PydanticArchive, ArchiveBase
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.server.server import SyncServer
from letta.validators import PATH_VALIDATORS
@@ -86,7 +86,7 @@ async def list_archives(
@router.patch("/{archive_id}", response_model=PydanticArchive, operation_id="modify_archive")
async def modify_archive(
archive: ArchiveUpdateRequest = Body(...),
archive_id: str = PATH_VALIDATORS["archive"],
archive_id: str = PATH_VALIDATORS[ArchiveBase.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):

View File

@@ -4,7 +4,7 @@ from fastapi import APIRouter, Body, Depends, HTTPException, Query
from letta.orm.errors import NoResultFound
from letta.schemas.agent import AgentState
from letta.schemas.block import Block, BlockUpdate, CreateBlock
from letta.schemas.block import BaseBlock, Block, BlockUpdate, CreateBlock
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.server.server import SyncServer
from letta.validators import PATH_VALIDATORS
@@ -129,7 +129,7 @@ async def create_block(
@router.patch("/{block_id}", response_model=Block, operation_id="modify_block")
async def modify_block(
block_id: str = PATH_VALIDATORS["block"],
block_id: str = PATH_VALIDATORS[BaseBlock.__id_prefix__],
block_update: BlockUpdate = Body(...),
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -140,7 +140,7 @@ async def modify_block(
@router.delete("/{block_id}", operation_id="delete_block")
async def delete_block(
block_id: str = PATH_VALIDATORS["block"],
block_id: str = PATH_VALIDATORS[BaseBlock.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -150,7 +150,7 @@ async def delete_block(
@router.get("/{block_id}", response_model=Block, operation_id="retrieve_block")
async def retrieve_block(
block_id: str = PATH_VALIDATORS["block"],
block_id: str = PATH_VALIDATORS[BaseBlock.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -163,7 +163,7 @@ async def retrieve_block(
@router.get("/{block_id}/agents", response_model=List[AgentState], operation_id="list_agents_for_block")
async def list_agents_for_block(
block_id: str = PATH_VALIDATORS["block"],
block_id: str = PATH_VALIDATORS[BaseBlock.__id_prefix__],
before: Optional[str] = Query(
None,
description="Agent ID cursor for pagination. Returns agents that come before this agent ID in the specified sort order",

View File

@@ -4,7 +4,7 @@ import tempfile
from pathlib import Path
from typing import List, Literal, Optional
from fastapi import APIRouter, Depends, HTTPException, Query, UploadFile
from fastapi import APIRouter, Depends, HTTPException, Path as PathParam, Query, UploadFile
from starlette import status
from starlette.responses import Response
@@ -21,10 +21,10 @@ from letta.otel.tracing import trace_method
from letta.schemas.agent import AgentState
from letta.schemas.embedding_config import EmbeddingConfig
from letta.schemas.enums import DuplicateFileHandling, FileProcessingStatus
from letta.schemas.file import FileMetadata
from letta.schemas.folder import Folder
from letta.schemas.file import FileMetadata, FileMetadataBase
from letta.schemas.folder import BaseFolder, Folder
from letta.schemas.passage import Passage
from letta.schemas.source import Source, SourceCreate, SourceUpdate
from letta.schemas.source import BaseSource, Source, SourceCreate, SourceUpdate
from letta.schemas.source_metadata import OrganizationSourcesStats
from letta.schemas.user import User
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
@@ -37,7 +37,7 @@ from letta.services.file_processor.parser.markitdown_parser import MarkitdownFil
from letta.services.file_processor.parser.mistral_parser import MistralFileParser
from letta.settings import settings
from letta.utils import safe_create_file_processing_task, safe_create_task, sanitize_filename
from letta.validators import PATH_VALIDATORS
from letta.validators import PATH_VALIDATORS, PRIMITIVE_ID_PATTERNS
logger = get_logger(__name__)
@@ -62,7 +62,7 @@ async def count_folders(
@router.get("/{folder_id}", response_model=Folder, operation_id="retrieve_folder")
async def retrieve_folder(
folder_id: str = PATH_VALIDATORS["folder"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -178,7 +178,7 @@ async def create_folder(
@router.patch("/{folder_id}", response_model=Folder, operation_id="modify_folder")
async def modify_folder(
folder: SourceUpdate,
folder_id: str = PATH_VALIDATORS["folder"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -193,7 +193,7 @@ async def modify_folder(
@router.delete("/{folder_id}", response_model=None, operation_id="delete_folder")
async def delete_folder(
folder_id: str = PATH_VALIDATORS["folder"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -229,7 +229,7 @@ async def delete_folder(
@router.post("/{folder_id}/upload", response_model=FileMetadata, operation_id="upload_file_to_folder")
async def upload_file_to_folder(
file: UploadFile,
folder_id: str = PATH_VALIDATORS["folder"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
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),
@@ -344,7 +344,7 @@ async def upload_file_to_folder(
@router.get("/{folder_id}/agents", response_model=List[str], operation_id="list_agents_for_folder")
async def list_agents_for_folder(
folder_id: str = PATH_VALIDATORS["folder"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
before: Optional[str] = Query(
None,
description="Agent ID cursor for pagination. Returns agents that come before this agent ID in the specified sort order",
@@ -377,7 +377,7 @@ async def list_agents_for_folder(
@router.get("/{folder_id}/passages", response_model=List[Passage], operation_id="list_folder_passages")
async def list_folder_passages(
folder_id: str = PATH_VALIDATORS["folder"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
before: Optional[str] = Query(
None,
description="Passage ID cursor for pagination. Returns passages that come before this passage ID in the specified sort order",
@@ -410,7 +410,7 @@ async def list_folder_passages(
@router.get("/{folder_id}/files", response_model=List[FileMetadata], operation_id="list_folder_files")
async def list_folder_files(
folder_id: str = PATH_VALIDATORS["folder"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
before: Optional[str] = Query(
None,
description="File ID cursor for pagination. Returns files that come before this file ID in the specified sort order",
@@ -497,8 +497,8 @@ async def list_folder_files(
# it's still good practice to return a status indicating the success or failure of the deletion
@router.delete("/{folder_id}/{file_id}", status_code=204, operation_id="delete_file_from_folder")
async def delete_file_from_folder(
folder_id: str = PATH_VALIDATORS["folder"],
file_id: str = PATH_VALIDATORS["file"],
folder_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[BaseFolder.__id_prefix__].pattern),
file_id: str = PathParam(..., pattern=PRIMITIVE_ID_PATTERNS[FileMetadataBase.__id_prefix__].pattern),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):

View File

@@ -5,10 +5,11 @@ from fastapi.responses import JSONResponse
from pydantic import Field
from letta.constants import DEFAULT_MESSAGE_TOOL, DEFAULT_MESSAGE_TOOL_KWARG
from letta.schemas.group import Group, GroupCreate, GroupUpdate, ManagerType
from letta.schemas.group import Group, GroupBase, GroupCreate, GroupUpdate, ManagerType
from letta.schemas.letta_message import LettaMessageUnion, LettaMessageUpdateUnion
from letta.schemas.letta_request import LettaRequest, LettaStreamingRequest
from letta.schemas.letta_response import LettaResponse
from letta.schemas.message import BaseMessage
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.server.server import SyncServer
from letta.validators import PATH_VALIDATORS
@@ -69,7 +70,7 @@ async def count_groups(
@router.get("/{group_id}", response_model=Group, operation_id="retrieve_group")
async def retrieve_group(
group_id: str = PATH_VALIDATORS["group"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -98,7 +99,7 @@ async def create_group(
@router.patch("/{group_id}", response_model=Group, operation_id="modify_group")
async def modify_group(
group_id: str = PATH_VALIDATORS["group"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
group: GroupUpdate = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -115,7 +116,7 @@ async def modify_group(
@router.delete("/{group_id}", response_model=None, operation_id="delete_group")
async def delete_group(
group_id: str = PATH_VALIDATORS["group"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -133,7 +134,7 @@ async def delete_group(
operation_id="send_group_message",
)
async def send_group_message(
group_id: str = PATH_VALIDATORS["group"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
request: LettaRequest = Body(...),
headers: HeaderParams = Depends(get_headers),
@@ -171,7 +172,7 @@ async def send_group_message(
},
)
async def send_group_message_streaming(
group_id: str = PATH_VALIDATORS["group"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
request: LettaStreamingRequest = Body(...),
headers: HeaderParams = Depends(get_headers),
@@ -203,8 +204,8 @@ GroupMessagesResponse = Annotated[
@router.patch("/{group_id}/messages/{message_id}", response_model=LettaMessageUnion, operation_id="modify_group_message")
async def modify_group_message(
group_id: str = PATH_VALIDATORS["group"],
message_id: str = PATH_VALIDATORS["message"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
message_id: str = PATH_VALIDATORS[BaseMessage.__id_prefix__],
request: LettaMessageUpdateUnion = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -219,7 +220,7 @@ async def modify_group_message(
@router.get("/{group_id}/messages", response_model=GroupMessagesResponse, operation_id="list_group_messages")
async def list_group_messages(
group_id: str = PATH_VALIDATORS["group"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
before: Optional[str] = Query(
None,
description="Message ID cursor for pagination. Returns messages that come before this message ID in the specified sort order",
@@ -274,7 +275,7 @@ async def list_group_messages(
@router.patch("/{group_id}/reset-messages", response_model=None, operation_id="reset_group_messages")
async def reset_group_messages(
group_id: str = PATH_VALIDATORS["group"],
group_id: str = PATH_VALIDATORS[GroupBase.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):

View File

@@ -5,7 +5,7 @@ from fastapi import APIRouter, Body, Depends, Header, Query
from letta.orm.errors import NoResultFound, UniqueConstraintViolationError
from letta.schemas.agent import AgentState
from letta.schemas.block import Block
from letta.schemas.identity import Identity, IdentityCreate, IdentityProperty, IdentityType, IdentityUpdate, IdentityUpsert
from letta.schemas.identity import Identity, IdentityBase, IdentityCreate, IdentityProperty, IdentityType, IdentityUpdate, IdentityUpsert
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.validators import PATH_VALIDATORS
@@ -73,7 +73,7 @@ async def count_identities(
@router.get("/{identity_id}", tags=["identities"], response_model=Identity, operation_id="retrieve_identity")
async def retrieve_identity(
identity_id: str = PATH_VALIDATORS["identity"],
identity_id: str = PATH_VALIDATORS[IdentityBase.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -109,7 +109,7 @@ async def upsert_identity(
@router.patch("/{identity_id}", tags=["identities"], response_model=Identity, operation_id="update_identity")
async def modify_identity(
identity_id: str = PATH_VALIDATORS["identity"],
identity_id: str = PATH_VALIDATORS[IdentityBase.__id_prefix__],
identity: IdentityUpdate = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -120,7 +120,7 @@ async def modify_identity(
@router.put("/{identity_id}/properties", tags=["identities"], operation_id="upsert_identity_properties")
async def upsert_identity_properties(
identity_id: str = PATH_VALIDATORS["identity"],
identity_id: str = PATH_VALIDATORS[IdentityBase.__id_prefix__],
properties: List[IdentityProperty] = Body(...),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -131,7 +131,7 @@ async def upsert_identity_properties(
@router.delete("/{identity_id}", tags=["identities"], operation_id="delete_identity")
async def delete_identity(
identity_id: str = PATH_VALIDATORS["identity"],
identity_id: str = PATH_VALIDATORS[IdentityBase.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -144,7 +144,7 @@ async def delete_identity(
@router.get("/{identity_id}/agents", response_model=List[AgentState], operation_id="list_agents_for_identity")
async def list_agents_for_identity(
identity_id: str = PATH_VALIDATORS["identity"],
identity_id: str = PATH_VALIDATORS[IdentityBase.__id_prefix__],
before: Optional[str] = Query(
None,
description="Agent ID cursor for pagination. Returns agents that come before this agent ID in the specified sort order",
@@ -177,7 +177,7 @@ async def list_agents_for_identity(
@router.get("/{identity_id}/blocks", response_model=List[Block], operation_id="list_blocks_for_identity")
async def list_blocks_for_identity(
identity_id: str = PATH_VALIDATORS["identity"],
identity_id: str = PATH_VALIDATORS[IdentityBase.__id_prefix__],
before: Optional[str] = Query(
None,
description="Block ID cursor for pagination. Returns blocks that come before this block ID in the specified sort order",

View File

@@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends, Query
from letta.errors import LettaInvalidArgumentError
from letta.schemas.enums import JobStatus
from letta.schemas.job import Job
from letta.schemas.job import Job, JobBase
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.server.server import SyncServer
from letta.settings import settings
@@ -89,7 +89,7 @@ async def list_active_jobs(
@router.get("/{job_id}", response_model=Job, operation_id="retrieve_job")
async def retrieve_job(
job_id: str = PATH_VALIDATORS["job"],
job_id: str = PATH_VALIDATORS[JobBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: "SyncServer" = Depends(get_letta_server),
):
@@ -102,7 +102,7 @@ async def retrieve_job(
@router.patch("/{job_id}/cancel", response_model=Job, operation_id="cancel_job")
async def cancel_job(
job_id: str = PATH_VALIDATORS["job"],
job_id: str = PATH_VALIDATORS[JobBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: "SyncServer" = Depends(get_letta_server),
):
@@ -127,7 +127,7 @@ async def cancel_job(
@router.delete("/{job_id}", response_model=Job, operation_id="delete_job")
async def delete_job(
job_id: str = PATH_VALIDATORS["job"],
job_id: str = PATH_VALIDATORS[JobBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: "SyncServer" = Depends(get_letta_server),
):

View File

@@ -4,7 +4,7 @@ from fastapi import APIRouter, Body, Depends, Query, status
from fastapi.responses import JSONResponse
from letta.schemas.enums import ProviderType
from letta.schemas.providers import Provider, ProviderCheck, ProviderCreate, ProviderUpdate
from letta.schemas.providers import Provider, ProviderBase, ProviderCheck, ProviderCreate, ProviderUpdate
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.validators import PATH_VALIDATORS
@@ -46,7 +46,7 @@ async def list_providers(
@router.get("/{provider_id}", response_model=Provider, operation_id="retrieve_provider")
async def retrieve_provider(
provider_id: str = PATH_VALIDATORS["provider"],
provider_id: str = PATH_VALIDATORS[ProviderBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: "SyncServer" = Depends(get_letta_server),
):
@@ -81,7 +81,7 @@ async def create_provider(
@router.patch("/{provider_id}", response_model=Provider, operation_id="modify_provider")
async def modify_provider(
request: ProviderUpdate = Body(...),
provider_id: str = PATH_VALIDATORS["provider"],
provider_id: str = PATH_VALIDATORS[ProviderBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: "SyncServer" = Depends(get_letta_server),
):
@@ -111,7 +111,7 @@ async def check_provider(
@router.post("/{provider_id}/check", response_model=None, operation_id="check_existing_provider")
async def check_existing_provider(
provider_id: str = PATH_VALIDATORS["provider"],
provider_id: str = PATH_VALIDATORS[ProviderBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: "SyncServer" = Depends(get_letta_server),
):
@@ -136,7 +136,7 @@ async def check_existing_provider(
@router.delete("/{provider_id}", response_model=None, operation_id="delete_provider")
async def delete_provider(
provider_id: str = PATH_VALIDATORS["provider"],
provider_id: str = PATH_VALIDATORS[ProviderBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: "SyncServer" = Depends(get_letta_server),
):

View File

@@ -15,6 +15,7 @@ from letta.schemas.environment_variables import (
from letta.schemas.sandbox_config import (
LocalSandboxConfig,
SandboxConfig as PydanticSandboxConfig,
SandboxConfigBase,
SandboxConfigCreate,
SandboxConfigUpdate,
)
@@ -89,7 +90,7 @@ async def create_custom_local_sandbox_config(
@router.patch("/{sandbox_config_id}", response_model=PydanticSandboxConfig)
async def update_sandbox_config(
config_update: SandboxConfigUpdate,
sandbox_config_id: str = PATH_VALIDATORS["sandbox"],
sandbox_config_id: str = PATH_VALIDATORS[SandboxConfigBase.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -99,7 +100,7 @@ async def update_sandbox_config(
@router.delete("/{sandbox_config_id}", status_code=204)
async def delete_sandbox_config(
sandbox_config_id: str = PATH_VALIDATORS["sandbox"],
sandbox_config_id: str = PATH_VALIDATORS[SandboxConfigBase.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -159,7 +160,7 @@ async def force_recreate_local_sandbox_venv(
@router.post("/{sandbox_config_id}/environment-variable", response_model=PydanticEnvVar)
async def create_sandbox_env_var(
env_var_create: SandboxEnvironmentVariableCreate,
sandbox_config_id: str = PATH_VALIDATORS["sandbox"],
sandbox_config_id: str = PATH_VALIDATORS[SandboxConfigBase.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -190,7 +191,7 @@ async def delete_sandbox_env_var(
@router.get("/{sandbox_config_id}/environment-variable", response_model=List[PydanticEnvVar])
async def list_sandbox_env_vars(
sandbox_config_id: str = PATH_VALIDATORS["sandbox"],
sandbox_config_id: str = PATH_VALIDATORS[SandboxConfigBase.__id_prefix__],
limit: int = Query(1000, description="Number of results to return"),
after: Optional[str] = Query(None, description="Pagination cursor to fetch the next set of results"),
server: SyncServer = Depends(get_letta_server),

View File

@@ -21,9 +21,9 @@ from letta.otel.tracing import trace_method
from letta.schemas.agent import AgentState
from letta.schemas.embedding_config import EmbeddingConfig
from letta.schemas.enums import DuplicateFileHandling, FileProcessingStatus
from letta.schemas.file import FileMetadata
from letta.schemas.file import FileMetadata, FileMetadataBase
from letta.schemas.passage import Passage
from letta.schemas.source import Source, SourceCreate, SourceUpdate
from letta.schemas.source import BaseSource, Source, SourceCreate, SourceUpdate
from letta.schemas.source_metadata import OrganizationSourcesStats
from letta.schemas.user import User
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
@@ -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 = PATH_VALIDATORS["source"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -158,7 +158,7 @@ async def create_source(
@router.patch("/{source_id}", response_model=Source, operation_id="modify_source", deprecated=True)
async def modify_source(
source: SourceUpdate,
source_id: str = PATH_VALIDATORS["source"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
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 = PATH_VALIDATORS["source"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
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 = PATH_VALIDATORS["source"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
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 = PATH_VALIDATORS["source"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
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 = PATH_VALIDATORS["source"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
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 = PATH_VALIDATORS["source"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
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"),
@@ -387,8 +387,8 @@ async def list_source_files(
@router.get("/{source_id}/files/{file_id}", response_model=FileMetadata, operation_id="get_file_metadata", deprecated=True)
async def get_file_metadata(
source_id: str = PATH_VALIDATORS["source"],
file_id: str = PATH_VALIDATORS["file"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
file_id: str = PATH_VALIDATORS[FileMetadataBase.__id_prefix__],
include_content: bool = Query(False, description="Whether to include full file content"),
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
@@ -413,8 +413,8 @@ async def get_file_metadata(
# it's still good practice to return a status indicating the success or failure of the deletion
@router.delete("/{source_id}/{file_id}", status_code=204, operation_id="delete_file_from_source", deprecated=True)
async def delete_file_from_source(
source_id: str = PATH_VALIDATORS["source"],
file_id: str = PATH_VALIDATORS["file"],
source_id: str = PATH_VALIDATORS[BaseSource.__id_prefix__],
file_id: str = PATH_VALIDATORS[FileMetadataBase.__id_prefix__],
server: "SyncServer" = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):

View File

@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field
from letta.schemas.letta_message import LettaMessageUnion
from letta.schemas.message import Message
from letta.schemas.provider_trace import ProviderTrace
from letta.schemas.step import Step
from letta.schemas.step import Step, StepBase
from letta.schemas.step_metrics import StepMetrics
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.server.server import SyncServer
@@ -70,7 +70,7 @@ async def list_steps(
@router.get("/{step_id}", response_model=Step, operation_id="retrieve_step")
async def retrieve_step(
step_id: str = PATH_VALIDATORS["step"],
step_id: str = PATH_VALIDATORS[StepBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: SyncServer = Depends(get_letta_server),
):
@@ -83,7 +83,7 @@ async def retrieve_step(
@router.get("/{step_id}/metrics", response_model=StepMetrics, operation_id="retrieve_metrics_for_step")
async def retrieve_metrics_for_step(
step_id: str = PATH_VALIDATORS["step"],
step_id: str = PATH_VALIDATORS[StepBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: SyncServer = Depends(get_letta_server),
):
@@ -96,7 +96,7 @@ async def retrieve_metrics_for_step(
@router.get("/{step_id}/trace", response_model=Optional[ProviderTrace], operation_id="retrieve_trace_for_step")
async def retrieve_trace_for_step(
step_id: str = PATH_VALIDATORS["step"],
step_id: str = PATH_VALIDATORS[StepBase.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -120,7 +120,7 @@ class ModifyFeedbackRequest(BaseModel):
@router.patch("/{step_id}/feedback", response_model=Step, operation_id="modify_feedback_for_step")
async def modify_feedback_for_step(
request: ModifyFeedbackRequest = Body(...),
step_id: str = PATH_VALIDATORS["step"],
step_id: str = PATH_VALIDATORS[StepBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: SyncServer = Depends(get_letta_server),
):
@@ -133,7 +133,7 @@ async def modify_feedback_for_step(
@router.get("/{step_id}/messages", response_model=List[LettaMessageUnion], operation_id="list_messages_for_step")
async def list_messages_for_step(
step_id: str = PATH_VALIDATORS["step"],
step_id: str = PATH_VALIDATORS[StepBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: SyncServer = Depends(get_letta_server),
before: Optional[str] = Query(
@@ -161,7 +161,7 @@ async def list_messages_for_step(
@router.patch("/{step_id}/transaction/{transaction_id}", response_model=Step, operation_id="update_step_transaction_id")
async def update_step_transaction_id(
transaction_id: str,
step_id: str = PATH_VALIDATORS["step"],
step_id: str = PATH_VALIDATORS[StepBase.__id_prefix__],
headers: HeaderParams = Depends(get_headers),
server: SyncServer = Depends(get_letta_server),
):

View File

@@ -30,7 +30,7 @@ from letta.schemas.letta_message_content import TextContent
from letta.schemas.mcp import UpdateSSEMCPServer, UpdateStdioMCPServer, UpdateStreamableHTTPMCPServer
from letta.schemas.message import Message
from letta.schemas.pip_requirement import PipRequirement
from letta.schemas.tool import Tool, ToolCreate, ToolRunFromSource, ToolUpdate
from letta.schemas.tool import BaseTool, Tool, ToolCreate, ToolRunFromSource, ToolUpdate
from letta.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
from letta.server.rest_api.streaming_response import StreamingResponseWithStatusCode
from letta.server.server import SyncServer
@@ -47,7 +47,7 @@ logger = get_logger(__name__)
@router.delete("/{tool_id}", operation_id="delete_tool")
async def delete_tool(
tool_id: str = PATH_VALIDATORS["tool"],
tool_id: str = PATH_VALIDATORS[BaseTool.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -150,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 = PATH_VALIDATORS["tool"],
tool_id: str = PATH_VALIDATORS[BaseTool.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):
@@ -299,7 +299,7 @@ async def upsert_tool(
@router.patch("/{tool_id}", response_model=Tool, operation_id="modify_tool")
async def modify_tool(
request: ToolUpdate = Body(...),
tool_id: str = PATH_VALIDATORS["tool"],
tool_id: str = PATH_VALIDATORS[BaseTool.__id_prefix__],
server: SyncServer = Depends(get_letta_server),
headers: HeaderParams = Depends(get_headers),
):

View File

@@ -2,25 +2,42 @@ import re
from fastapi import Path
from letta.schemas.agent import AgentState
from letta.schemas.archive import ArchiveBase
from letta.schemas.block import BaseBlock
from letta.schemas.file import FileMetadataBase
from letta.schemas.folder import BaseFolder
from letta.schemas.group import GroupBase
from letta.schemas.identity import IdentityBase
from letta.schemas.job import JobBase
from letta.schemas.message import BaseMessage
from letta.schemas.providers import ProviderBase
from letta.schemas.run import RunBase
from letta.schemas.sandbox_config import SandboxConfigBase
from letta.schemas.source import BaseSource
from letta.schemas.step import StepBase
from letta.schemas.tool import BaseTool
# TODO: extract this list from routers/v1/__init__.py and ROUTERS
primitives = [
"agent",
"message",
"run",
"job",
"group",
"block",
"file",
"folder",
"source",
"tool",
"archive",
"provider",
"sandbox",
"step",
"identity",
AgentState.__id_prefix__,
BaseMessage.__id_prefix__,
RunBase.__id_prefix__,
JobBase.__id_prefix__,
GroupBase.__id_prefix__,
BaseBlock.__id_prefix__,
FileMetadataBase.__id_prefix__,
BaseFolder.__id_prefix__,
BaseSource.__id_prefix__,
BaseTool.__id_prefix__,
ArchiveBase.__id_prefix__,
ProviderBase.__id_prefix__,
SandboxConfigBase.__id_prefix__,
StepBase.__id_prefix__,
IdentityBase.__id_prefix__,
]
PRIMITIVE_ID_PATTERNS = {
# f-string interpolation gets confused because of the regex's required curly braces {}
primitive: re.compile("^" + primitive + "-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")