Repository: griptape-ai/griptape

Issue:
No way to set `References` when chunking text
It would be helpful to be able to set `reference` on chunks when chunking an artifact.

```python
from griptape.chunkers import TextChunker, ChunkSeparator
from griptape.common import Reference
from rich import print

text = """
Apple:
    - I love the taste of apples
    - I love the taste of cinnamon

Pumpkin:
    - I'm a fan of pumpkin
    - I love the taste of nutmeg

Meat:
    - I like savory pies
    - I'm a fan of all things from New Zealand
"""

# create reference
reference = Reference(authors=["jason"], title="pies I like")

# How do I set reference information?
chunker = TextChunker(max_tokens=24, separators=[ChunkSeparator("\n\n")]).chunk(text)
```

Even if you create a `TextArtifact` and explicitly set the `reference`, it doesn't stick around after being chunked.

```python
reference = Reference(authors=["jason"], title="pies I like")

artifact = TextArtifact(text, reference=reference)
print ("Original Artifact:")
print(artifact)

chunker = TextChunker(max_tokens=24, separators=[ChunkSeparator("\n\n")]).chunk(artifact)
print("\nChunks:")
print(chunker)
```

and the result:
```
Original Artifact:
TextArtifact(
    type='TextArtifact',
    module_name='griptape.artifacts.text_artifact',
    id='cf5743ff02454edeb55065dfa32bc2d3',
    reference=Reference(type='Reference', module_name='griptape.common.reference', id='32c5b7fe99844f9e88b1232caa3a33dd', title='pies I like', authors=['jason'], source=None, year=None, url=None),
    meta={},
    name='cf5743ff02454edeb55065dfa32bc2d3',
    encoding_error_handler='strict',
    encoding='utf-8',
    value="\nApple:\n    - I love the taste of apples\n    - I love the taste of cinnamon\n\nPumpkin:\n    - I'm a fan of pumpkin\n    - I love the taste of nutmeg\n\nMeat:\n    - I like savory pies\n    - I'm a fan of all things from New        
Zealand\n",
    embedding=None
)

Chunks:
[
    TextArtifact(
        type='TextArtifact',
        module_name='griptape.artifacts.text_artifact',
        id='0f6c4e33a79b4cb49ba72779c7b197fa',
        reference=None,
        meta={},
        name='0f6c4e33a79b4cb49ba72779c7b197fa',
        encoding_error_handler='strict',
        encoding='utf-8',
        value='Apple:\n    - I love the taste of apples\n    - I love the taste of cinnamon',
        embedding=None
    ),
    TextArtifact(
        type='TextArtifact',
        module_name='griptape.artifacts.text_artifact',
        id='ed3346f28f5149e7b6429f0640e1b68a',
        reference=None,
        meta={},
        name='ed3346f28f5149e7b6429f0640e1b68a',
        encoding_error_handler='strict',
        encoding='utf-8',
        value="Pumpkin:\n    - I'm a fan of pumpkin\n    - I love the taste of nutmeg",
        embedding=None
    ),
    TextArtifact(
        type='TextArtifact',
        module_name='griptape.artifacts.text_artifact',
        id='837adf66c58f4c7bb14e147416ce4e0f',
        reference=None,
        meta={},
        name='837adf66c58f4c7bb14e147416ce4e0f',
        encoding_error_handler='strict',
        encoding='utf-8',
        value="Meat:\n    - I like savory pies\n    - I'm a fan of all things from New Zealand",
        embedding=None
    )
]
```

Hints from issue comments:

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f11af48..f223506d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - `BaseChunker` chunking more than necessary.
 - `BaseLoader.reference` not being set when using `BaseLoader.parse` directly.
 - `LocalVectorStoreDriver` returned Entries not containing the namespace.
+- References being lost on Artifacts during chunking.
 
 ### Deprecated
 
diff --git a/griptape/chunkers/base_chunker.py b/griptape/chunkers/base_chunker.py
index c93ef5d2..fa32e559 100644
--- a/griptape/chunkers/base_chunker.py
+++ b/griptape/chunkers/base_chunker.py
@@ -5,8 +5,7 @@ from typing import Optional
 
 from attrs import Attribute, Factory, define, field
 
-from griptape.artifacts import TextArtifact
-from griptape.artifacts.list_artifact import ListArtifact
+from griptape.artifacts import ListArtifact, TextArtifact
 from griptape.chunkers import ChunkSeparator
 from griptape.tokenizers import BaseTokenizer, OpenAiTokenizer
 
@@ -34,9 +33,10 @@ class BaseChunker(ABC):
             raise ValueError("max_tokens must be 0 or greater.")
 
     def chunk(self, text: TextArtifact | ListArtifact | str) -> list[TextArtifact]:
-        text = text.to_text() if isinstance(text, (TextArtifact, ListArtifact)) else text
+        text_to_chunk = text if isinstance(text, str) else text.to_text()
+        reference = None if isinstance(text, str) else text.reference
 
-        return [TextArtifact(c) for c in self._chunk_recursively(text)]
+        return [TextArtifact(c, reference=reference) for c in self._chunk_recursively(text_to_chunk)]
 
     def _chunk_recursively(self, chunk: str, current_separator: Optional[ChunkSeparator] = None) -> list[str]:
         token_count = self.tokenizer.count_tokens(chunk)


Test patch:
diff --git a/tests/unit/chunkers/test_text_chunker.py b/tests/unit/chunkers/test_text_chunker.py
index 99f83d94..ee1b2152 100644
--- a/tests/unit/chunkers/test_text_chunker.py
+++ b/tests/unit/chunkers/test_text_chunker.py
@@ -123,3 +123,17 @@ class TestTextChunker:
         assert len(chunks) == 2
         for chunk in chunks:
             assert chunker.tokenizer.count_tokens(chunk.value) <= max_tokens
+
+    def test_artifact_reference(self, chunker):
+        from griptape.common.reference import Reference
+
+        reference = Reference(authors=["jason"], title="pies I like")
+        chunks = chunker.chunk(TextArtifact(gen_paragraph(MAX_TOKENS * 2, chunker.tokenizer, " "), reference=reference))
+
+        for chunk in chunks:
+            assert chunk.reference == reference
+
+        chunks = chunker.chunk(gen_paragraph(MAX_TOKENS * 2, chunker.tokenizer, " "))
+
+        for chunk in chunks:
+            assert chunk.reference is None