ragaai-catalyst 2.2.2b1__py3-none-any.whl → 2.2.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. ragaai_catalyst/dataset.py +41 -43
  2. ragaai_catalyst/evaluation.py +16 -25
  3. ragaai_catalyst/guard_executor.py +8 -8
  4. ragaai_catalyst/ragaai_catalyst.py +4 -9
  5. ragaai_catalyst/tracers/agentic_tracing/upload/trace_uploader.py +15 -14
  6. ragaai_catalyst/tracers/agentic_tracing/upload/upload_code.py +8 -12
  7. ragaai_catalyst/tracers/agentic_tracing/utils/api_utils.py +4 -1
  8. ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +182 -144
  9. ragaai_catalyst/tracers/agentic_tracing/utils/span_attributes.py +6 -3
  10. ragaai_catalyst/tracers/distributed.py +6 -3
  11. ragaai_catalyst/tracers/exporters/dynamic_trace_exporter.py +4 -4
  12. ragaai_catalyst/tracers/exporters/file_span_exporter.py +1 -3
  13. ragaai_catalyst/tracers/exporters/raga_exporter.py +2 -2
  14. ragaai_catalyst/tracers/exporters/ragaai_trace_exporter.py +3 -3
  15. ragaai_catalyst/tracers/tracer.py +68 -92
  16. ragaai_catalyst/tracers/utils/model_prices_and_context_window_backup.json +6131 -2218
  17. ragaai_catalyst/tracers/utils/trace_json_converter.py +141 -92
  18. ragaai_catalyst/tracers/utils/utils.py +1 -1
  19. {ragaai_catalyst-2.2.2b1.dist-info → ragaai_catalyst-2.2.3.dist-info}/METADATA +1 -1
  20. {ragaai_catalyst-2.2.2b1.dist-info → ragaai_catalyst-2.2.3.dist-info}/RECORD +23 -23
  21. {ragaai_catalyst-2.2.2b1.dist-info → ragaai_catalyst-2.2.3.dist-info}/WHEEL +1 -1
  22. {ragaai_catalyst-2.2.2b1.dist-info → ragaai_catalyst-2.2.3.dist-info}/licenses/LICENSE +0 -0
  23. {ragaai_catalyst-2.2.2b1.dist-info → ragaai_catalyst-2.2.3.dist-info}/top_level.txt +0 -0
@@ -76,14 +76,14 @@ class DynamicTraceExporter(SpanExporter):
76
76
  # Update the exporter's properties
77
77
  self._update_exporter_properties()
78
78
  except Exception as e:
79
- raise Exception(f"Error updating exporter properties: {e}")
79
+ logger.error(f"Error updating exporter properties: {e}")
80
80
 
81
81
  try:
82
82
  # Forward the call to the underlying exporter
83
83
  result = self._exporter.export(spans)
84
84
  return result
85
85
  except Exception as e:
86
- raise Exception(f"Error exporting trace: {e}")
86
+ logger.error(f"Error exporting trace: {e}")
87
87
 
88
88
 
89
89
 
@@ -96,13 +96,13 @@ class DynamicTraceExporter(SpanExporter):
96
96
  # Update the exporter's properties
97
97
  self._update_exporter_properties()
98
98
  except Exception as e:
99
- raise Exception(f"Error updating exporter properties: {e}")
99
+ logger.error(f"Error updating exporter properties: {e}")
100
100
 
101
101
  try:
102
102
  # Forward the call to the underlying exporter
103
103
  return self._exporter.shutdown()
104
104
  except Exception as e:
105
- raise Exception(f"Error shutting down exporter: {e}")
105
+ logger.error(f"Error shutting down exporter: {e}")
106
106
 
107
107
  def _update_exporter_properties(self):
108
108
  """
@@ -136,9 +136,7 @@ class FileSpanExporter(SpanExporter):
136
136
  """
137
137
  async with aiohttp.ClientSession() as session:
138
138
  if not os.getenv("RAGAAI_CATALYST_TOKEN"):
139
- raise ValueError(
140
- "RAGAAI_CATALYST_TOKEN not found. Cannot upload traces."
141
- )
139
+ logger.error("RAGAAI_CATALYST_TOKEN not found. Cannot upload traces.")
142
140
 
143
141
  try:
144
142
  upload_stat = await self.raga_client.check_and_upload_files(
@@ -60,7 +60,7 @@ class RagaExporter:
60
60
  self.secret_key = os.getenv("RAGAAI_CATALYST_SECRET_KEY")
61
61
  self.max_urls = 20
62
62
  if not self.access_key or not self.secret_key:
63
- raise ValueError(
63
+ logger.error(
64
64
  "RAGAAI_CATALYST_ACCESS_KEY and RAGAAI_CATALYST_SECRET_KEY environment variables must be set"
65
65
  )
66
66
  if not os.getenv("RAGAAI_CATALYST_TOKEN"):
@@ -68,7 +68,7 @@ class RagaExporter:
68
68
 
69
69
  create_status_code = self._create_schema()
70
70
  if create_status_code != 200:
71
- raise Exception(
71
+ logger.error(
72
72
  "Failed to create schema. Please consider raising an issue."
73
73
  )
74
74
  # elif status_code != 200:
@@ -51,7 +51,7 @@ class RAGATraceExporter(SpanExporter):
51
51
  span_json = json.loads(span.to_json())
52
52
  trace_id = span_json.get("context").get("trace_id")
53
53
  if trace_id is None:
54
- raise Exception("Trace ID is None")
54
+ logger.error("Trace ID is None")
55
55
 
56
56
  if trace_id not in self.trace_spans:
57
57
  self.trace_spans[trace_id] = list()
@@ -63,11 +63,11 @@ class RAGATraceExporter(SpanExporter):
63
63
  try:
64
64
  self.process_complete_trace(trace, trace_id)
65
65
  except Exception as e:
66
- raise Exception(f"Error processing complete trace: {e}")
66
+ logger.error(f"Error processing complete trace: {e}")
67
67
  try:
68
68
  del self.trace_spans[trace_id]
69
69
  except Exception as e:
70
- raise Exception(f"Error deleting trace: {e}")
70
+ logger.error(f"Error deleting trace: {e}")
71
71
  except Exception as e:
72
72
  logger.warning(f"Error processing span: {e}")
73
73
  continue
@@ -1,26 +1,35 @@
1
- import asyncio
1
+ import os
2
+ import uuid
2
3
  import datetime
3
- import json
4
4
  import logging
5
- import os
6
- from concurrent.futures import ThreadPoolExecutor
7
- from contextlib import contextmanager
8
- from pathlib import Path
9
-
5
+ import asyncio
10
6
  import aiohttp
11
7
  import requests
12
8
  from litellm import model_cost
9
+ from pathlib import Path
10
+ from contextlib import contextmanager
11
+ from concurrent.futures import ThreadPoolExecutor
12
+ from ragaai_catalyst.tracers.langchain_callback import LangchainTracer
13
+ from ragaai_catalyst.tracers.utils.convert_langchain_callbacks_output import convert_langchain_callbacks_output
13
14
 
14
- # from ragaai_catalyst.tracers.llamaindex_callback import LlamaIndexTracer
15
- from openinference.instrumentation.langchain import LangChainInstrumentor
15
+ from ragaai_catalyst.tracers.utils.langchain_tracer_extraction_logic import langchain_tracer_extraction
16
+ from ragaai_catalyst.tracers.upload_traces import UploadTraces
17
+ import tempfile
18
+ import json
19
+ import numpy as np
16
20
  from opentelemetry.sdk import trace as trace_sdk
17
21
  from opentelemetry.sdk.trace.export import SimpleSpanProcessor
18
-
22
+ from ragaai_catalyst.tracers.exporters.file_span_exporter import FileSpanExporter
23
+ from ragaai_catalyst.tracers.exporters.raga_exporter import RagaExporter
24
+ from ragaai_catalyst.tracers.utils import get_unique_key
25
+ # from ragaai_catalyst.tracers.llamaindex_callback import LlamaIndexTracer
26
+ from ragaai_catalyst.tracers.llamaindex_instrumentation import LlamaIndexInstrumentationTracer
27
+ from openinference.instrumentation.langchain import LangChainInstrumentor
19
28
  from ragaai_catalyst import RagaAICatalyst
20
29
  from ragaai_catalyst.tracers.agentic_tracing import AgenticTracing
30
+ from ragaai_catalyst.tracers.agentic_tracing.tracers.llm_tracer import LLMTracerMixin
31
+ from ragaai_catalyst.tracers.exporters.ragaai_trace_exporter import RAGATraceExporter
21
32
  from ragaai_catalyst.tracers.agentic_tracing.utils.file_name_tracker import TrackName
22
- from ragaai_catalyst.tracers.exporters.file_span_exporter import FileSpanExporter
23
- from ragaai_catalyst.tracers.utils import get_unique_key
24
33
 
25
34
  logger = logging.getLogger(__name__)
26
35
  logging_level = (
@@ -157,7 +166,7 @@ class Tracer(AgenticTracing):
157
166
  project["name"] for project in response.json()["data"]["content"]
158
167
  ]
159
168
  if project_name not in project_list:
160
- raise ValueError("Project not found. Please enter a valid project name")
169
+ logger.error("Project not found. Please enter a valid project name")
161
170
 
162
171
  self.project_id = [
163
172
  project["id"] for project in response.json()["data"]["content"] if project["name"] == project_name
@@ -168,7 +177,6 @@ class Tracer(AgenticTracing):
168
177
 
169
178
  except requests.exceptions.RequestException as e:
170
179
  logger.error(f"Failed to retrieve projects list: {e}")
171
- raise
172
180
 
173
181
  # if tracer_type == "langchain":
174
182
  # instrumentors = []
@@ -191,16 +199,12 @@ class Tracer(AgenticTracing):
191
199
  # Add LLM Instrumentors
192
200
  if tracer_type in ['agentic/crewai']:
193
201
  try:
194
- from openinference.instrumentation.vertexai import (
195
- VertexAIInstrumentor,
196
- )
202
+ from openinference.instrumentation.vertexai import VertexAIInstrumentor
197
203
  instrumentors.append((VertexAIInstrumentor, []))
198
204
  except (ImportError, ModuleNotFoundError):
199
205
  logger.debug("VertexAI not available in environment")
200
206
  try:
201
- from openinference.instrumentation.anthropic import (
202
- AnthropicInstrumentor,
203
- )
207
+ from openinference.instrumentation.anthropic import AnthropicInstrumentor
204
208
  instrumentors.append((AnthropicInstrumentor, []))
205
209
  except (ImportError, ModuleNotFoundError):
206
210
  logger.debug("Anthropic not available in environment")
@@ -210,16 +214,12 @@ class Tracer(AgenticTracing):
210
214
  except (ImportError, ModuleNotFoundError):
211
215
  logger.debug("Groq not available in environment")
212
216
  try:
213
- from openinference.instrumentation.litellm import (
214
- LiteLLMInstrumentor,
215
- )
217
+ from openinference.instrumentation.litellm import LiteLLMInstrumentor
216
218
  instrumentors.append((LiteLLMInstrumentor, []))
217
219
  except (ImportError, ModuleNotFoundError):
218
220
  logger.debug("LiteLLM not available in environment")
219
221
  try:
220
- from openinference.instrumentation.mistralai import (
221
- MistralAIInstrumentor,
222
- )
222
+ from openinference.instrumentation.mistralai import MistralAIInstrumentor
223
223
  instrumentors.append((MistralAIInstrumentor, []))
224
224
  except (ImportError, ModuleNotFoundError):
225
225
  logger.debug("MistralAI not available in environment")
@@ -229,9 +229,7 @@ class Tracer(AgenticTracing):
229
229
  except (ImportError, ModuleNotFoundError):
230
230
  logger.debug("OpenAI not available in environment")
231
231
  try:
232
- from openinference.instrumentation.bedrock import (
233
- BedrockInstrumentor,
234
- )
232
+ from openinference.instrumentation.bedrock import BedrockInstrumentor
235
233
  instrumentors.append((BedrockInstrumentor, []))
236
234
  except (ImportError, ModuleNotFoundError):
237
235
  logger.debug("Bedrock not available in environment")
@@ -244,9 +242,7 @@ class Tracer(AgenticTracing):
244
242
  try:
245
243
  # LlamaIndex
246
244
  try:
247
- from openinference.instrumentation.llama_index import (
248
- LlamaIndexInstrumentor,
249
- )
245
+ from openinference.instrumentation.llama_index import LlamaIndexInstrumentor
250
246
  instrumentors.append((LlamaIndexInstrumentor, []))
251
247
  logger.info("Instrumenting LlamaIndex...")
252
248
  except (ImportError, ModuleNotFoundError):
@@ -254,9 +250,7 @@ class Tracer(AgenticTracing):
254
250
 
255
251
  # LangChain
256
252
  try:
257
- from openinference.instrumentation.langchain import (
258
- LangChainInstrumentor,
259
- )
253
+ from openinference.instrumentation.langchain import LangChainInstrumentor
260
254
  instrumentors.append((LangChainInstrumentor, []))
261
255
  logger.info("Instrumenting LangChain...")
262
256
  except (ImportError, ModuleNotFoundError):
@@ -264,9 +258,7 @@ class Tracer(AgenticTracing):
264
258
 
265
259
  # CrewAI
266
260
  try:
267
- from openinference.instrumentation.crewai import (
268
- CrewAIInstrumentor,
269
- )
261
+ from openinference.instrumentation.crewai import CrewAIInstrumentor
270
262
  instrumentors.append((CrewAIInstrumentor, []))
271
263
  logger.info("Instrumenting CrewAI...")
272
264
  except (ImportError, ModuleNotFoundError):
@@ -274,9 +266,7 @@ class Tracer(AgenticTracing):
274
266
 
275
267
  # Haystack
276
268
  try:
277
- from openinference.instrumentation.haystack import (
278
- HaystackInstrumentor,
279
- )
269
+ from openinference.instrumentation.haystack import HaystackInstrumentor
280
270
  instrumentors.append((HaystackInstrumentor, []))
281
271
  logger.info("Instrumenting Haystack...")
282
272
  except (ImportError, ModuleNotFoundError):
@@ -284,9 +274,7 @@ class Tracer(AgenticTracing):
284
274
 
285
275
  # AutoGen
286
276
  try:
287
- from openinference.instrumentation.autogen import (
288
- AutogenInstrumentor,
289
- )
277
+ from openinference.instrumentation.autogen import AutogenInstrumentor
290
278
  instrumentors.append((AutogenInstrumentor, []))
291
279
  logger.info("Instrumenting AutoGen...")
292
280
  except (ImportError, ModuleNotFoundError):
@@ -294,9 +282,7 @@ class Tracer(AgenticTracing):
294
282
 
295
283
  # Smolagents
296
284
  try:
297
- from openinference.instrumentation.smolagents import (
298
- SmolagentsInstrumentor,
299
- )
285
+ from openinference.instrumentation.smolagents import SmolagentsInstrumentor
300
286
  instrumentors.append((SmolagentsInstrumentor, []))
301
287
  logger.info("Instrumenting Smolagents...")
302
288
  except (ImportError, ModuleNotFoundError):
@@ -304,9 +290,7 @@ class Tracer(AgenticTracing):
304
290
 
305
291
  # OpenAI Agents
306
292
  try:
307
- from openinference.instrumentation.openai_agents import (
308
- OpenAIAgentsInstrumentor,
309
- )
293
+ from openinference.instrumentation.openai_agents import OpenAIAgentsInstrumentor
310
294
  instrumentors.append((OpenAIAgentsInstrumentor, []))
311
295
  logger.info("Instrumenting OpenAI Agents...")
312
296
  except (ImportError, ModuleNotFoundError):
@@ -324,22 +308,16 @@ class Tracer(AgenticTracing):
324
308
 
325
309
  # Handle specific framework instrumentation
326
310
  elif tracer_type == "agentic/llamaindex" or tracer_type == "llamaindex":
327
- from openinference.instrumentation.llama_index import (
328
- LlamaIndexInstrumentor,
329
- )
311
+ from openinference.instrumentation.llama_index import LlamaIndexInstrumentor
330
312
  instrumentors += [(LlamaIndexInstrumentor, [])]
331
313
 
332
314
  elif tracer_type == "agentic/langchain" or tracer_type == "agentic/langgraph" or tracer_type == "langchain":
333
- from openinference.instrumentation.langchain import (
334
- LangChainInstrumentor,
335
- )
315
+ from openinference.instrumentation.langchain import LangChainInstrumentor
336
316
  instrumentors += [(LangChainInstrumentor, [])]
337
317
 
338
318
  elif tracer_type == "agentic/crewai":
339
319
  from openinference.instrumentation.crewai import CrewAIInstrumentor
340
- from openinference.instrumentation.langchain import (
341
- LangChainInstrumentor,
342
- )
320
+ from openinference.instrumentation.langchain import LangChainInstrumentor
343
321
  instrumentors += [(CrewAIInstrumentor, []), (LangChainInstrumentor, [])]
344
322
 
345
323
  elif tracer_type == "agentic/haystack":
@@ -351,15 +329,11 @@ class Tracer(AgenticTracing):
351
329
  instrumentors += [(AutogenInstrumentor, [])]
352
330
 
353
331
  elif tracer_type == "agentic/smolagents":
354
- from openinference.instrumentation.smolagents import (
355
- SmolagentsInstrumentor,
356
- )
332
+ from openinference.instrumentation.smolagents import SmolagentsInstrumentor
357
333
  instrumentors += [(SmolagentsInstrumentor, [])]
358
334
 
359
335
  elif tracer_type == "agentic/openai_agents":
360
- from openinference.instrumentation.openai_agents import (
361
- OpenAIAgentsInstrumentor,
362
- )
336
+ from openinference.instrumentation.openai_agents import OpenAIAgentsInstrumentor
363
337
  instrumentors += [(OpenAIAgentsInstrumentor, [])]
364
338
 
365
339
  else:
@@ -391,20 +365,23 @@ class Tracer(AgenticTracing):
391
365
  "output_cost_per_million_token": 2.40
392
366
  })
393
367
  """
394
- if not isinstance(cost_config, dict):
395
- raise TypeError("cost_config must be a dictionary")
396
-
397
- required_keys = {"model_name", "input_cost_per_million_token", "output_cost_per_million_token"}
398
- if not all(key in cost_config for key in required_keys):
399
- raise ValueError(f"cost_config must contain all required keys: {required_keys}")
400
-
401
- model_name = cost_config["model_name"]
402
- self.model_custom_cost[model_name] = {
403
- "input_cost_per_token": float(cost_config["input_cost_per_million_token"])/ 1000000,
404
- "output_cost_per_token": float(cost_config["output_cost_per_million_token"]) /1000000
405
- }
406
- self.dynamic_exporter.custom_model_cost = self.model_custom_cost
407
- logger.info(f"Updated custom model cost for {model_name}: {self.model_custom_cost[model_name]}")
368
+ logger.info("DEPRECATED: The set_model_cost method is deprecated and will be removed in a future version. Custom model costs can now be configured directly through the RagaAI Catalyst Platform")
369
+ print("DEPRECATED: The set_model_cost method is deprecated and will be removed in a future version. Custom model costs can now be configured directly through the RagaAI Catalyst Platform")
370
+ # if not isinstance(cost_config, dict):
371
+ # logger.error("cost_config must be a dictionary")
372
+
373
+ # required_keys = {"model_name", "input_cost_per_million_token", "output_cost_per_million_token"}
374
+ # if not all(key in cost_config for key in required_keys):
375
+ # logger.error(f"cost_config must contain all required keys: {required_keys}")
376
+
377
+ # model_name = cost_config["model_name"]
378
+ # self.model_custom_cost[model_name] = {
379
+ # "input_cost_per_token": float(cost_config["input_cost_per_million_token"])/ 1000000,
380
+ # "output_cost_per_token": float(cost_config["output_cost_per_million_token"]) /1000000
381
+ # }
382
+ # self.dynamic_exporter.custom_model_cost = self.model_custom_cost
383
+ # logger.info(f"Updated custom model cost for {model_name}: {self.model_custom_cost[model_name]}")
384
+ return None
408
385
 
409
386
 
410
387
  def register_masking_function(self, masking_func):
@@ -425,7 +402,7 @@ class Tracer(AgenticTracing):
425
402
  return value
426
403
  """
427
404
  if not callable(masking_func):
428
- raise TypeError("masking_func must be a callable")
405
+ logger.error("masking_func must be a callable")
429
406
 
430
407
  def recursive_mask_values(obj, parent_key=None):
431
408
  """Apply masking to all values in nested structure."""
@@ -440,7 +417,11 @@ class Tracer(AgenticTracing):
440
417
  'start_time', 'end_time', 'name', 'id',
441
418
  'hash_id', 'parent_id', 'source_hash_id',
442
419
  'cost', 'type', 'feedback', 'error', 'ctx','telemetry.sdk.version',
443
- 'telemetry.sdk.language','service.name'
420
+ 'telemetry.sdk.language','service.name', 'llm.model_name',
421
+ 'llm.invocation_parameters', 'metadata', 'openinference.span.kind',
422
+ 'llm.token_count.prompt', 'llm.token_count.completion', 'llm.token_count.total',
423
+ "input_cost", "output_cost", "total_cost", "status_code", "output.mime_type",
424
+ "span_id", "trace_id"
444
425
  }
445
426
  # Apply masking only if the key is NOT in the excluded list
446
427
  if parent_key and parent_key.lower() not in excluded_keys:
@@ -497,7 +478,7 @@ class Tracer(AgenticTracing):
497
478
  def post_processor_func(original_trace_json_path: os.PathLike) -> os.PathLike
498
479
  """
499
480
  if not callable(post_processor_func):
500
- raise TypeError("post_processor_func must be a callable")
481
+ logger.error("post_processor_func must be a callable")
501
482
  self.post_processor = post_processor_func
502
483
  # Register in parent AgenticTracing class
503
484
  super().register_post_processor(post_processor_func)
@@ -600,7 +581,7 @@ class Tracer(AgenticTracing):
600
581
  "llama_index": LlamaIndexInstrumentor,
601
582
  }
602
583
  if tracer_type not in instrumentors:
603
- raise ValueError(f"Invalid tracer type: {tracer_type}")
584
+ logger.error(f"Invalid tracer type: {tracer_type}")
604
585
  return instrumentors[tracer_type]().get()
605
586
 
606
587
  @contextmanager
@@ -721,9 +702,7 @@ class Tracer(AgenticTracing):
721
702
  """
722
703
  async with aiohttp.ClientSession() as session:
723
704
  if not os.getenv("RAGAAI_CATALYST_TOKEN"):
724
- raise ValueError(
725
- "RAGAAI_CATALYST_TOKEN not found. Cannot upload traces."
726
- )
705
+ logger.error("RAGAAI_CATALYST_TOKEN not found. Cannot upload traces.")
727
706
 
728
707
  try:
729
708
  upload_stat = await asyncio.wait_for(
@@ -807,7 +786,7 @@ class Tracer(AgenticTracing):
807
786
  AttributeError: If the tracer_type is not an agentic tracer or if the dynamic_exporter is not initialized.
808
787
  """
809
788
  if not self.tracer_type.startswith("agentic/") or not hasattr(self, "dynamic_exporter"):
810
- raise AttributeError("This method is only available for agentic tracers with a dynamic exporter.")
789
+ logger.error("This method is only available for agentic tracers with a dynamic exporter.")
811
790
 
812
791
  for key, value in kwargs.items():
813
792
  if hasattr(self.dynamic_exporter, key):
@@ -825,10 +804,7 @@ class Tracer(AgenticTracing):
825
804
  """
826
805
  from opentelemetry.sdk import trace as trace_sdk
827
806
  from opentelemetry.sdk.trace.export import SimpleSpanProcessor
828
-
829
- from ragaai_catalyst.tracers.exporters.dynamic_trace_exporter import (
830
- DynamicTraceExporter,
831
- )
807
+ from ragaai_catalyst.tracers.exporters.dynamic_trace_exporter import DynamicTraceExporter
832
808
 
833
809
  # Get the code_files
834
810
  self.file_tracker.trace_main_file()
@@ -877,7 +853,7 @@ class Tracer(AgenticTracing):
877
853
  AttributeError: If the tracer_type is not 'agentic/llamaindex' or if the dynamic_exporter is not initialized.
878
854
  """
879
855
  if not self.tracer_type.startswith("agentic/") or not hasattr(self, "dynamic_exporter"):
880
- raise AttributeError("This method is only available for agentic tracers with a dynamic exporter.")
856
+ logger.error("This method is only available for agentic tracers with a dynamic exporter.")
881
857
 
882
858
  # Get the latest list of unique files
883
859
  list_of_unique_files = self.file_tracker.get_unique_files()