Repository: truera/trulens
Issue: [Recursion Error] Calling TruLlama() 
Root cause: Algorithmic Error

**RecursionError: maximum recursion depth exceeded**

```
import os
from llama_index.core import  VectorStoreIndex, get_response_synthesizer, Settings, StorageContext, PromptTemplate, load_index_from_storage, SimpleDirectoryReader
from llama_index.llms.huggingface import HuggingFaceLLM
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from trulens_eval import Feedback, Select

# HuggingFace API key
os.environ["HUGGINGFACE_TOKEN"] = "hf_RyUYYSrF----------VStqeKYsj"

#Openai API key
os.environ["OPENAI_API_KEY"] = "sk-7N1V337g-----7jQGT3BlbkFJVo-----enMlKbnHhW"

# Configure custom embedding model
embed_model = HuggingFaceEmbedding(model_name="wahid028/GIST-Law-Embed")
Settings.embed_model = embed_model

# Configure custom llm
hf_token = "hf_YCZNvLuVr-----ZQcdbNVQhWdvb"

from transformers import AutoTokenizer

HF_model = "meta-llama/Meta-Llama-3-8B"

tokenizer = AutoTokenizer.from_pretrained(
    HF_model,
    token=hf_token,
)

stopping_ids = [
    tokenizer.eos_token_id,
    tokenizer.convert_tokens_to_ids("
"),
]

llm = HuggingFaceLLM(
    model_name=HF_model,
    model_kwargs={
        "token": hf_token,
        "torch_dtype": torch.bfloat16,  # comment this line and uncomment below to use 4bit
    },
    generate_kwargs={
        "do_sample": True,
        "temperature": 0.7,
        "top_p": 0.9,
    },

    tokenizer_name= HF_model,
    tokenizer_kwargs={"token": hf_token},
    stopping_ids=stopping_ids,
)

Settings.llm = llm

#Configure RAG
documents = SimpleDirectoryReader("../RAG/data").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine(similarity_top_k=3)

response = query_engine.query("What are the .....?")
print(str(response))

eval_questions = []
with open('eval_questions.txt', 'r') as file:
    for line in file:
        # Remove newline character and convert to integer
        item = line.strip()
        print(item)
        eval_questions.append(item)
        
# You can try your own question:
new_question = "What are the primary objectives ..?"
eval_questions.append(new_question)

#Calling TruLens
from trulens_eval import Tru
tru = Tru()

tru.reset_database()

from trulens_eval.feedback.provider.openai import OpenAI
import numpy as np

# Initialize provider class
provider = OpenAI()

# select context to be used in feedback. the location of context is app specific.
from trulens_eval.app import App
context = App.select_context(query_engine)

# Define a groundedness feedback function
f_groundedness = (
    Feedback(provider.groundedness_measure_with_cot_reasons)
    .on(context.collect()) # collect context chunks into a list
    .on_output()
)

# Question/answer relevance between overall question and answer.
f_answer_relevance = (
    Feedback(provider.relevance)
    .on_input_output()
)
# Question/statement relevance between question and each context chunk.
f_context_relevance = (
    Feedback(provider.context_relevance_with_cot_reasons)
    .on_input()
    .on(context)
    .aggregate(np.mean)
)

from trulens_eval import TruLlama
tru_query_engine_recorder = TruLlama(query_engine,
    app_id='LlamaIndex_App1',
    feedbacks=[f_groundedness, f_answer_relevance, f_context_relevance])
```

<!-- Greeting -->
Hey there, @wahidur028! I'm a bot here to help you with bugs, questions, and becoming a contributor. Let's tackle this together while waiting for a human maintainer.

<!-- Answer -->
The `RecursionError: maximum recursion depth exceeded` is likely caused by the recursive call in the `TruLlama` class. Specifically, the `root_callable` is set to `TruLlama.query`, which might be causing an infinite recursion.

To resolve this issue, you can modify the `root_callable` to avoid the recursive call. Here is the corrected part of the `TruLlama` class:

```python
class TruLlama(mod_app.App):
    """Recorder for _LlamaIndex_ applications."""

    model_config: ClassVar[dict] = dict(arbitrary_types_allowed=True)

    app: Union[BaseQueryEngine, BaseChatEngine]

    root_callable: ClassVar[FunctionOrMethod] = Field(
        default_factory=lambda: FunctionOrMethod.of_callable(mod_app.App.query)
    )

    def __init__(
        self, app: Union[BaseQueryEngine, BaseChatEngine], **kwargs: dict
    ):
        # TruLlama specific:
        kwargs['app'] = app
        kwargs['root_class'] = Class.of_object(app)  # TODO: make class property
        kwargs['instrument'] = LlamaInstrument(app=self)

        super().__init__(**kwargs)

    @classmethod
    def select_source_nodes(cls) -> Lens:
        """
        Get the path to the source nodes in the query output.
        """
        return cls.select_outputs().source_nodes[:]

    @classmethod
    def select_context(
        cls,
        app: Optional[Union[BaseQueryEngine, BaseChatEngine]] = None
    ) -> Lens:
        """
        Get the path to the context in the query output.
        """
        return cls.select_outputs().source_nodes[:].node.text
```

By changing `TruLlama.query` to `mod_app.App.query` in the `root_callable`, you avoid the recursive call that leads to the `RecursionError` <sup>[[1]](https://github.com/truera/trulens/blob/main/trulens_eval/trulens_eval/tru_llama.py)</sup>.

Additionally, ensure that you are correctly initializing and using the `TruLlama` class as shown in the example:

```python
from trulens_eval import TruLlama

tru_query_engine_recorder = TruLlama(
    query_engine,
    app_id='LlamaIndex_App1',
    feedbacks=[f_groundedness, f_answer_relevance, f_context_relevance]
)

# or as context manager
with tru_query_engine_recorder as recording:
    query_engine.query("What did the author do growing up?")
```

This ensures that the `TruLlama` instance is properly set up and used, avoiding potential recursion issues <sup>[[1]](https://github.com/truera/trulens/blob/main/trulens_eval/trulens_eval/tru_llama.py)</sup>.


<!-- Dosu Comment Footer -->
*To continue talking to [Dosu](https://dosu.dev), mention @dosu.*


Hi; can you check whether the branch in this PR fixes the problem: https://github.com/truera/trulens/pull/1176 ?

Hi @piotrm0, I still get the same error after modifying the `TruLlama() `class mentioned above.



> Hi @piotrm0, I still get the same error after modifying the `TruLlama() `class mentioned above.

Please ignore dosubot here. I meant to try using the trulens_eval that is in the branch referenced by this PR: https://github.com/truera/trulens/pull/1176 . See the main readme on how to install from a branch.

@piotrm0, please guide me on how to resolve the issue below. 
```
(llms) in**@inf**:~/wahid/projects$ pip install git+https://github.com/piotrm0/trulens.git@piotrm/jsonify-stack-size-protect

Collecting git+https://github.com/piotrm0/trulens.git@piotrm/jsonify-stack-size-protect
  Cloning https://github.com/piotrm0/trulens.git (to revision piotrm/jsonify-stack-size-protect) to /tmp/pip-req-build-ozpwrdwg
  Running command git clone --filter=blob:none --quiet https://github.com/piotrm0/trulens.git /tmp/pip-req-build-ozpwrdwg
  Running command git checkout -b piotrm/jsonify-stack-size-protect --track origin/piotrm/jsonify-stack-size-protect
  Switched to a new branch 'piotrm/jsonify-stack-size-protect'
  Branch 'piotrm/jsonify-stack-size-protect' set up to track remote branch 'piotrm/jsonify-stack-size-protect' from 'origin'.
  Resolved https://github.com/piotrm0/trulens.git to commit 466d079a6dde4ae637123c30f89dbf2d0adba761

ERROR: git+https://github.com/piotrm0/trulens.git@piotrm/jsonify-stack-size-protect does not appear to be a Python project: neither 'setup.py' nor 'pyproject.toml' found.
```

@wahidur028 , don't forget to include `#subdirectory=trulens_eval` are the end of the package address as in
```
git+https://github.com/piotrm0/trulens.git@piotrm/jsonify-stack-size-protect#subdirectory=trulens_eval
```

@wahidur028 were you able to have success installing as Piotr mentioned?

@piotrm0 @sfc-gh-jreini It's working now. Thanks for your help.