diff --git a/letta/services/tool_executor/multi_agent_tool_executor.py b/letta/services/tool_executor/multi_agent_tool_executor.py index 901e2022..8ecfc569 100644 --- a/letta/services/tool_executor/multi_agent_tool_executor.py +++ b/letta/services/tool_executor/multi_agent_tool_executor.py @@ -80,10 +80,13 @@ class LettaMultiAgentToolExecutor(ToolExecutor): f"{message}" ) - # Run concurrent requests and collect their return values. - # Note: Do not wrap with safe_create_task here — it swallows return values (returns None). - coros = [self._process_agent(agent_state=a_state, message=augmented_message, actor=actor) for a_state in matching_agents] - results = await asyncio.gather(*coros) + # Process agents sequentially to avoid exhausting the database connection pool. + # When many agents match the tags, concurrent execution can create too many simultaneous + # database connections, causing pool exhaustion errors. + results = [] + for agent_state in matching_agents: + result = await self._process_agent(agent_state=agent_state, message=augmented_message, actor=actor) + results.append(result) return str(results) async def _process_agent(self, agent_state: AgentState, message: str, actor: User) -> Dict[str, Any]: