diff --git a/fern/openapi.json b/fern/openapi.json index 29cb4eed..f3ebc9a0 100644 --- a/fern/openapi.json +++ b/fern/openapi.json @@ -10549,6 +10549,24 @@ }, "description": "Whether to sort agents oldest to newest (True) or newest to oldest (False, default). Deprecated in favor of order field.", "deprecated": true + }, + { + "name": "project_id", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Filter runs by project ID.", + "title": "Project Id" + }, + "description": "Filter runs by project ID." } ], "responses": { diff --git a/letta/server/rest_api/routers/v1/internal_runs.py b/letta/server/rest_api/routers/v1/internal_runs.py index fa603d23..7c8d8525 100644 --- a/letta/server/rest_api/routers/v1/internal_runs.py +++ b/letta/server/rest_api/routers/v1/internal_runs.py @@ -62,6 +62,7 @@ async def list_runs( description="Whether to sort agents oldest to newest (True) or newest to oldest (False, default). Deprecated in favor of order field.", deprecated=True, ), + project_id: Optional[str] = Query(None, description="Filter runs by project ID."), headers: HeaderParams = Depends(get_headers), ): """ @@ -103,5 +104,6 @@ async def list_runs( step_count=step_count, step_count_operator=step_count_operator, tools_used=tools_used, + project_id=project_id, ) return runs diff --git a/letta/services/run_manager.py b/letta/services/run_manager.py index 6c16d5e3..ca6b74ce 100644 --- a/letta/services/run_manager.py +++ b/letta/services/run_manager.py @@ -14,7 +14,7 @@ from letta.orm.run_metrics import RunMetrics as RunMetricsModel from letta.orm.sqlalchemy_base import AccessType from letta.orm.step import Step as StepModel from letta.otel.tracing import log_event, trace_method -from letta.schemas.enums import AgentType, ComparisonOperator, MessageRole, RunStatus, PrimitiveType +from letta.schemas.enums import AgentType, ComparisonOperator, MessageRole, PrimitiveType, RunStatus from letta.schemas.job import LettaRequestConfig from letta.schemas.letta_message import LettaMessage, LettaMessageUnion from letta.schemas.letta_response import LettaResponse @@ -112,6 +112,7 @@ class RunManager: step_count: Optional[int] = None, step_count_operator: ComparisonOperator = ComparisonOperator.EQ, tools_used: Optional[List[str]] = None, + project_id: Optional[str] = None, ) -> List[PydanticRun]: """List runs with filtering options.""" async with db_registry.async_session() as session: @@ -119,6 +120,10 @@ class RunManager: query = select(RunModel).filter(RunModel.organization_id == actor.organization_id) + # Filter by project_id if provided + if project_id: + query = query.filter(RunModel.project_id == project_id) + # Handle agent filtering if agent_id: agent_ids = [agent_id]