feat: add new identity agent and blocks routes (#2934)
This commit is contained in:
@@ -955,6 +955,18 @@ paths:
|
||||
- identities
|
||||
- properties
|
||||
x-fern-sdk-method-name: upsert
|
||||
/v1/identities/{identity_id}/agents:
|
||||
get:
|
||||
x-fern-sdk-group-name:
|
||||
- identities
|
||||
- agents
|
||||
x-fern-sdk-method-name: list
|
||||
/v1/identities/{identity_id}/blocks:
|
||||
get:
|
||||
x-fern-sdk-group-name:
|
||||
- identities
|
||||
- blocks
|
||||
x-fern-sdk-method-name: list
|
||||
/v1/groups/:
|
||||
get:
|
||||
x-fern-sdk-group-name:
|
||||
|
||||
@@ -3,6 +3,8 @@ from typing import TYPE_CHECKING, List, Literal, Optional
|
||||
from fastapi import APIRouter, Body, Depends, Header, HTTPException, 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.server.rest_api.dependencies import HeaderParams, get_headers, get_letta_server
|
||||
|
||||
@@ -192,3 +194,79 @@ async def delete_identity(
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"{e}")
|
||||
|
||||
|
||||
@router.get("/{identity_id}/agents", response_model=List[AgentState], operation_id="list_agents_for_identity")
|
||||
async def list_agents_for_identity(
|
||||
identity_id: str,
|
||||
before: Optional[str] = Query(
|
||||
None,
|
||||
description="Agent ID cursor for pagination. Returns agents that come before this agent ID in the specified sort order",
|
||||
),
|
||||
after: Optional[str] = Query(
|
||||
None,
|
||||
description="Agent ID cursor for pagination. Returns agents that come after this agent ID in the specified sort order",
|
||||
),
|
||||
limit: Optional[int] = Query(50, description="Maximum number of agents to return"),
|
||||
order: Literal["asc", "desc"] = Query(
|
||||
"desc", description="Sort order for agents by creation time. 'asc' for oldest first, 'desc' for newest first"
|
||||
),
|
||||
order_by: Literal["created_at"] = Query("created_at", description="Field to sort by"),
|
||||
server: "SyncServer" = Depends(get_letta_server),
|
||||
headers: HeaderParams = Depends(get_headers),
|
||||
):
|
||||
"""
|
||||
Get all agents associated with the specified identity.
|
||||
"""
|
||||
try:
|
||||
actor = await server.user_manager.get_actor_or_default_async(actor_id=headers.actor_id)
|
||||
return await server.identity_manager.list_agents_for_identity_async(
|
||||
identity_id=identity_id,
|
||||
before=before,
|
||||
after=after,
|
||||
limit=limit,
|
||||
ascending=(order == "asc"),
|
||||
actor=actor,
|
||||
)
|
||||
except NoResultFound as e:
|
||||
raise HTTPException(status_code=404, detail=f"Identity with id={identity_id} not found")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"{e}")
|
||||
|
||||
|
||||
@router.get("/{identity_id}/blocks", response_model=List[Block], operation_id="list_blocks_for_identity")
|
||||
async def list_blocks_for_identity(
|
||||
identity_id: str,
|
||||
before: Optional[str] = Query(
|
||||
None,
|
||||
description="Block ID cursor for pagination. Returns blocks that come before this block ID in the specified sort order",
|
||||
),
|
||||
after: Optional[str] = Query(
|
||||
None,
|
||||
description="Block ID cursor for pagination. Returns blocks that come after this block ID in the specified sort order",
|
||||
),
|
||||
limit: Optional[int] = Query(50, description="Maximum number of blocks to return"),
|
||||
order: Literal["asc", "desc"] = Query(
|
||||
"desc", description="Sort order for blocks by creation time. 'asc' for oldest first, 'desc' for newest first"
|
||||
),
|
||||
order_by: Literal["created_at"] = Query("created_at", description="Field to sort by"),
|
||||
server: "SyncServer" = Depends(get_letta_server),
|
||||
headers: HeaderParams = Depends(get_headers),
|
||||
):
|
||||
"""
|
||||
Get all blocks associated with the specified identity.
|
||||
"""
|
||||
try:
|
||||
actor = await server.user_manager.get_actor_or_default_async(actor_id=headers.actor_id)
|
||||
return await server.identity_manager.list_blocks_for_identity_async(
|
||||
identity_id=identity_id,
|
||||
before=before,
|
||||
after=after,
|
||||
limit=limit,
|
||||
ascending=(order == "asc"),
|
||||
actor=actor,
|
||||
)
|
||||
except NoResultFound as e:
|
||||
raise HTTPException(status_code=404, detail=f"Identity with id={identity_id} not found")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"{e}")
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import HTTPException
|
||||
@@ -9,6 +10,8 @@ from letta.orm.block import Block as BlockModel
|
||||
from letta.orm.errors import UniqueConstraintViolationError
|
||||
from letta.orm.identity import Identity as IdentityModel
|
||||
from letta.otel.tracing import trace_method
|
||||
from letta.schemas.agent import AgentState
|
||||
from letta.schemas.block import Block
|
||||
from letta.schemas.identity import (
|
||||
Identity as PydanticIdentity,
|
||||
IdentityCreate,
|
||||
@@ -274,3 +277,65 @@ class IdentityManager:
|
||||
current_ids = {item.id for item in current_relationship}
|
||||
new_items = [item for item in found_items if item.id not in current_ids]
|
||||
current_relationship.extend(new_items)
|
||||
|
||||
@enforce_types
|
||||
@trace_method
|
||||
async def list_agents_for_identity_async(
|
||||
self,
|
||||
identity_id: str,
|
||||
before: Optional[str] = None,
|
||||
after: Optional[str] = None,
|
||||
limit: Optional[int] = 50,
|
||||
ascending: bool = False,
|
||||
actor: PydanticUser = None,
|
||||
) -> List[AgentState]:
|
||||
"""
|
||||
Get all agents associated with the specified identity.
|
||||
"""
|
||||
async with db_registry.async_session() as session:
|
||||
# First verify the identity exists and belongs to the user
|
||||
identity = await IdentityModel.read_async(db_session=session, identifier=identity_id, actor=actor)
|
||||
if identity is None:
|
||||
raise HTTPException(status_code=404, detail=f"Identity with id={identity_id} not found")
|
||||
|
||||
# Get agents associated with this identity with pagination
|
||||
agents = await AgentModel.list_async(
|
||||
db_session=session,
|
||||
before=before,
|
||||
after=after,
|
||||
limit=limit,
|
||||
ascending=ascending,
|
||||
identity_id=identity.id,
|
||||
)
|
||||
return await asyncio.gather(*[agent.to_pydantic_async() for agent in agents])
|
||||
|
||||
@enforce_types
|
||||
@trace_method
|
||||
async def list_blocks_for_identity_async(
|
||||
self,
|
||||
identity_id: str,
|
||||
before: Optional[str] = None,
|
||||
after: Optional[str] = None,
|
||||
limit: Optional[int] = 50,
|
||||
ascending: bool = False,
|
||||
actor: PydanticUser = None,
|
||||
) -> List[Block]:
|
||||
"""
|
||||
Get all blocks associated with the specified identity.
|
||||
"""
|
||||
async with db_registry.async_session() as session:
|
||||
# First verify the identity exists and belongs to the user
|
||||
identity = await IdentityModel.read_async(db_session=session, identifier=identity_id, actor=actor)
|
||||
if identity is None:
|
||||
raise HTTPException(status_code=404, detail=f"Identity with id={identity_id} not found")
|
||||
|
||||
# Get blocks associated with this identity with pagination
|
||||
blocks = await BlockModel.list_async(
|
||||
db_session=session,
|
||||
before=before,
|
||||
after=after,
|
||||
limit=limit,
|
||||
ascending=ascending,
|
||||
identity_id=identity.id,
|
||||
)
|
||||
return [block.to_pydantic() for block in blocks]
|
||||
|
||||
Reference in New Issue
Block a user