Repository: phidatahq/phidata
File: libs/agno/agno/os/app.py (Python)

Code before:
            self.interfaces.append(a2a_interface)
            self._add_router(app, a2a_interface.get_router())

    def _check_duplicate_ids(
        self,
        entities: Optional[List[Any]],
    ) -> None:
        """Check for duplicate IDs in a list of entities.

        Args:
            entities: List of agents, teams, or workflows

        Raises:
            ValueError: If duplicate IDs are found
        """
        if not entities:
            return

        seen_ids: List[str] = []

        for entity in entities:
            entity_id = entity.id
            # If id is None, generate it the same way initialization does
            if entity_id is None:
                if hasattr(entity, "name") and entity.name:
                    entity_id = generate_id_from_name(entity.name)
                else:
                    continue  # Will get unique UUID during initialization

            if entity_id in seen_ids:
                raise ValueError(f"Duplicate IDs found in AgentOS: '{entity_id}'")
            seen_ids.append(entity_id)

    def _make_app(self, lifespan: Optional[Any] = None) -> FastAPI:
        # Adjust the FastAPI app lifespan to handle MCP connections if relevant
        app_lifespan = lifespan
        if self.mcp_tools is not None:
            mcp_tools_lifespan = partial(mcp_lifespan, mcp_tools=self.mcp_tools)
            # If there is already a lifespan, combine it with the MCP lifespan
            if lifespan is not None:
                # Combine both lifespans
                @asynccontextmanager
                async def combined_lifespan(app: FastAPI):
                    # Run both lifespans
                    async with lifespan(app):  # type: ignore
                        async with mcp_tools_lifespan(app):  # type: ignore
                            yield

                app_lifespan = combined_lifespan
            else:
                app_lifespan = mcp_tools_lifespan

Review comment (refactor):
better to let the entities initialize and then check for duplicates, because

1. the logic there could change, outdating this bit
2. we would now be running this id generation stuff twice in the happy path, no need

Code after:
        """Check for duplicate IDs within each entity type.

        Raises:
            ValueError: If duplicate IDs are found within the same entity type
        """
        duplicate_ids: List[str] = []

        for entities in [self.agents, self.teams, self.workflows]:
            if not entities:
                continue
            seen_ids: set[str] = set()
            for entity in entities:
                entity_id = entity.id
                if entity_id is None:
                    continue
                if entity_id in seen_ids:
                    if entity_id not in duplicate_ids:
                        duplicate_ids.append(entity_id)
                else:
                    seen_ids.add(entity_id)

        if duplicate_ids:
            raise ValueError(f"Duplicate IDs found in AgentOS: {', '.join(repr(id_) for id_ in duplicate_ids)}")

    def _make_app(self, lifespan: Optional[Any] = None) -> FastAPI:
        # Adjust the FastAPI app lifespan to handle MCP connections if relevant
        app_lifespan = lifespan
        if self.mcp_tools is not None:
            mcp_tools_lifespan = partial(mcp_lifespan, mcp_tools=self.mcp_tools)
            # If there is already a lifespan, combine it with the MCP lifespan
            if lifespan is not None:
                # Combine both lifespans
                @asynccontextmanager
                async def combined_lifespan(app: FastAPI):
                    # Run both lifespans
                    async with lifespan(app):  # type: ignore
                        async with mcp_tools_lifespan(app):  # type: ignore
                            yield

                app_lifespan = combined_lifespan
            else:
                app_lifespan = mcp_tools_lifespan

        return FastAPI(
            title=self.name or "Agno AgentOS",
            version=self.version or "1.0.0",
            description=self.description or "An agent operating system.",
            docs_url="/docs" if self.settings.docs_enabled else None,
            redoc_url="/redoc" if self.settings.docs_enabled else None,
            openapi_url="/openapi.json" if self.settings.docs_enabled else None,
            lifespan=app_lifespan,