From bb2145c24cf6b86750cf88d5597338a23b7da0fe Mon Sep 17 00:00:00 2001 From: Shubham Naik Date: Wed, 28 Jan 2026 09:30:15 -0800 Subject: [PATCH] connections (#9113) * chore: release code * chore: release code * chore: release code * chore: release code * chore: release code * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: change paths * chore: remote * chore: support multi project chat --- fern/openapi.json | 111 ++++++++++++++++-- .../rest_api/routers/v1/conversations.py | 2 + letta/services/conversation_manager.py | 46 +++++++- 3 files changed, 151 insertions(+), 8 deletions(-) diff --git a/fern/openapi.json b/fern/openapi.json index 6e0d32fe..c10e53af 100644 --- a/fern/openapi.json +++ b/fern/openapi.json @@ -8492,6 +8492,24 @@ "title": "After" }, "description": "Cursor for pagination (conversation ID)" + }, + { + "name": "summary_search", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Search for text within conversation summaries", + "title": "Summary Search" + }, + "description": "Search for text within conversation summaries" } ], "responses": { @@ -23430,7 +23448,12 @@ }, "integration_type": { "type": "string", - "enum": ["slack", "custom_webhook"] + "enum": [ + "slack", + "discord", + "microsoftTeams", + "custom_webhook" + ] }, "producer_config": { "discriminator": { @@ -23544,7 +23567,12 @@ }, "integration_type": { "type": "string", - "enum": ["slack", "custom_webhook"] + "enum": [ + "slack", + "discord", + "microsoftTeams", + "custom_webhook" + ] }, "feed_id": { "type": "string" @@ -23644,6 +23672,12 @@ }, "error_count": { "type": "number" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string" } }, "required": [ @@ -23713,6 +23747,13 @@ "type": "string" } }, + { + "name": "integration_id", + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "offset", "in": "query", @@ -23767,7 +23808,12 @@ }, "integration_type": { "type": "string", - "enum": ["slack", "custom_webhook"] + "enum": [ + "slack", + "discord", + "microsoftTeams", + "custom_webhook" + ] }, "feed_id": { "type": "string" @@ -23867,6 +23913,12 @@ }, "error_count": { "type": "number" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string" } }, "required": [ @@ -23917,6 +23969,13 @@ "schema": { "type": "string" } + }, + { + "name": "integration_id", + "in": "query", + "schema": { + "type": "string" + } } ], "operationId": "pipelines.countPipelines", @@ -23985,7 +24044,12 @@ }, "integration_type": { "type": "string", - "enum": ["slack", "custom_webhook"] + "enum": [ + "slack", + "discord", + "microsoftTeams", + "custom_webhook" + ] }, "feed_id": { "type": "string" @@ -24085,6 +24149,12 @@ }, "error_count": { "type": "number" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string" } }, "required": [ @@ -24193,7 +24263,12 @@ }, "integration_type": { "type": "string", - "enum": ["slack", "custom_webhook"] + "enum": [ + "slack", + "discord", + "microsoftTeams", + "custom_webhook" + ] }, "feed_id": { "type": "string" @@ -24293,6 +24368,12 @@ }, "error_count": { "type": "number" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string" } }, "required": [ @@ -24523,7 +24604,12 @@ }, "integration_type": { "type": "string", - "enum": ["slack", "custom_webhook"] + "enum": [ + "slack", + "discord", + "microsoftTeams", + "custom_webhook" + ] }, "feed_id": { "type": "string" @@ -24623,6 +24709,12 @@ }, "error_count": { "type": "number" + }, + "project_name": { + "type": "string" + }, + "project_slug": { + "type": "string" } }, "required": [ @@ -24706,7 +24798,12 @@ "properties": { "integration_type": { "type": "string", - "enum": ["slack", "custom_webhook"] + "enum": [ + "slack", + "discord", + "microsoftTeams", + "custom_webhook" + ] }, "integration_id": { "type": "string" diff --git a/letta/server/rest_api/routers/v1/conversations.py b/letta/server/rest_api/routers/v1/conversations.py index 212fcd32..1269c9e9 100644 --- a/letta/server/rest_api/routers/v1/conversations.py +++ b/letta/server/rest_api/routers/v1/conversations.py @@ -61,6 +61,7 @@ async def list_conversations( agent_id: str = Query(..., description="The agent ID to list conversations for"), limit: int = Query(50, description="Maximum number of conversations to return"), after: Optional[str] = Query(None, description="Cursor for pagination (conversation ID)"), + summary_search: Optional[str] = Query(None, description="Search for text within conversation summaries"), server: SyncServer = Depends(get_letta_server), headers: HeaderParams = Depends(get_headers), ): @@ -71,6 +72,7 @@ async def list_conversations( actor=actor, limit=limit, after=after, + summary_search=summary_search, ) diff --git a/letta/services/conversation_manager.py b/letta/services/conversation_manager.py index e5c87a1a..101598fb 100644 --- a/letta/services/conversation_manager.py +++ b/letta/services/conversation_manager.py @@ -105,9 +105,53 @@ class ConversationManager: actor: PydanticUser, limit: int = 50, after: Optional[str] = None, + summary_search: Optional[str] = None, ) -> List[PydanticConversation]: - """List conversations for an agent with cursor-based pagination.""" + """List conversations for an agent with cursor-based pagination. + + Args: + agent_id: The agent ID to list conversations for + actor: The user performing the action + limit: Maximum number of conversations to return + after: Cursor for pagination (conversation ID) + summary_search: Optional text to search for within the summary field + + Returns: + List of conversations matching the criteria + """ async with db_registry.async_session() as session: + # If summary search is provided, use custom query + if summary_search: + from sqlalchemy import and_ + + stmt = ( + select(ConversationModel) + .where( + and_( + ConversationModel.agent_id == agent_id, + ConversationModel.organization_id == actor.organization_id, + ConversationModel.summary.isnot(None), + ConversationModel.summary.contains(summary_search), + ) + ) + .order_by(ConversationModel.created_at.desc()) + .limit(limit) + ) + + if after: + # Add cursor filtering + after_conv = await ConversationModel.read_async( + db_session=session, + identifier=after, + actor=actor, + ) + stmt = stmt.where(ConversationModel.created_at < after_conv.created_at) + + result = await session.execute(stmt) + conversations = result.scalars().all() + return [conv.to_pydantic() for conv in conversations] + + # Use default list logic conversations = await ConversationModel.list_async( db_session=session, actor=actor,