def METHOD_NAME(
    self,
    query_bundle: QueryBundle,
    query_id: Optional[str] = None,
    cur_similarity: Optional[float] = None,
) -> Tuple[List[NodeWithScore], List[NodeWithScore]]:
    """Query recursively."""
    if self._verbose:
        print_text(
            f"Retrieving with query id {query_id}: {query_bundle.query_str}\n",
            color="blue",
        )
    query_id = query_id or self._root_id
    cur_similarity = cur_similarity or 1.0
    obj = self._get_object(query_id)
    if isinstance(obj, BaseNode):
        nodes_to_add = [NodeWithScore(node=obj, score=cur_similarity)]
        additional_nodes: List[NodeWithScore] = []
    elif isinstance(obj, BaseRetriever):
        with self.callback_manager.event(
            CBEventType.RETRIEVE,
            payload={EventPayload.QUERY_STR: query_bundle.query_str},
        ) as event:
            nodes = obj.retrieve(query_bundle)
            event.on_end(payload={EventPayload.NODES: nodes})
        nodes_to_add, additional_nodes = self._query_retrieved_nodes(
            query_bundle, nodes
        )
    elif isinstance(obj, BaseQueryEngine):
        sub_resp = obj.query(query_bundle)
        if self._verbose:
            print_text(
                f"Got response: {str(sub_resp)}\n",
                color="green",
            )
        # format with both the query and the response
        node_text = self._query_response_tmpl.format(
            query_str=query_bundle.query_str, response=str(sub_resp)
        )
        node = TextNode(text=node_text)
        nodes_to_add = [NodeWithScore(node=node, score=cur_similarity)]
        additional_nodes = sub_resp.source_nodes
    else:
        raise ValueError("Must be a retriever or query engine.")
    return nodes_to_add, additional_nodes