trustgraph-base 2.2.12__tar.gz → 2.2.14__tar.gz

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 (159) hide show
  1. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/PKG-INFO +1 -1
  2. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/__init__.py +2 -0
  3. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/explainability.py +86 -48
  4. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/socket_client.py +6 -3
  5. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/types.py +5 -0
  6. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/graph_rag_client.py +2 -0
  7. trustgraph_base-2.2.14/trustgraph/base_version.py +1 -0
  8. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/provenance/__init__.py +4 -0
  9. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/provenance/agent.py +74 -35
  10. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/provenance/namespaces.py +1 -0
  11. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/provenance/triples.py +29 -9
  12. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/retrieval.py +1 -0
  13. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph_base.egg-info/PKG-INFO +1 -1
  14. trustgraph_base-2.2.12/trustgraph/base_version.py +0 -1
  15. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/README.md +0 -0
  16. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/pyproject.toml +0 -0
  17. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/setup.cfg +0 -0
  18. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/api.py +0 -0
  19. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/async_bulk_client.py +0 -0
  20. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/async_flow.py +0 -0
  21. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/async_metrics.py +0 -0
  22. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/async_socket_client.py +0 -0
  23. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/bulk_client.py +0 -0
  24. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/collection.py +0 -0
  25. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/config.py +0 -0
  26. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/exceptions.py +0 -0
  27. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/flow.py +0 -0
  28. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/knowledge.py +0 -0
  29. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/library.py +0 -0
  30. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/api/metrics.py +0 -0
  31. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/__init__.py +0 -0
  32. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/agent_client.py +0 -0
  33. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/agent_service.py +0 -0
  34. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/async_processor.py +0 -0
  35. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/backend.py +0 -0
  36. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/cassandra_config.py +0 -0
  37. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/chunking_service.py +0 -0
  38. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/collection_config_handler.py +0 -0
  39. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/consumer.py +0 -0
  40. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/consumer_spec.py +0 -0
  41. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/document_embeddings_client.py +0 -0
  42. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/document_embeddings_query_service.py +0 -0
  43. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/document_embeddings_store_service.py +0 -0
  44. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/dynamic_tool_service.py +0 -0
  45. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/embeddings_client.py +0 -0
  46. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/embeddings_service.py +0 -0
  47. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/flow.py +0 -0
  48. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/flow_processor.py +0 -0
  49. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/graph_embeddings_client.py +0 -0
  50. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/graph_embeddings_query_service.py +0 -0
  51. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/graph_embeddings_store_service.py +0 -0
  52. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/llm_service.py +0 -0
  53. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/logging.py +0 -0
  54. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/metrics.py +0 -0
  55. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/parameter_spec.py +0 -0
  56. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/producer.py +0 -0
  57. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/producer_spec.py +0 -0
  58. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/prompt_client.py +0 -0
  59. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/publisher.py +0 -0
  60. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/pubsub.py +0 -0
  61. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/pulsar_backend.py +0 -0
  62. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/request_response_spec.py +0 -0
  63. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/row_embeddings_query_client.py +0 -0
  64. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/spec.py +0 -0
  65. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/structured_query_client.py +0 -0
  66. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/subscriber.py +0 -0
  67. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/subscriber_spec.py +0 -0
  68. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/text_completion_client.py +0 -0
  69. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/tool_client.py +0 -0
  70. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/tool_service.py +0 -0
  71. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/tool_service_client.py +0 -0
  72. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/triples_client.py +0 -0
  73. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/triples_query_service.py +0 -0
  74. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/base/triples_store_service.py +0 -0
  75. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/__init__.py +0 -0
  76. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/agent_client.py +0 -0
  77. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/base.py +0 -0
  78. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/config_client.py +0 -0
  79. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/document_embeddings_client.py +0 -0
  80. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/document_rag_client.py +0 -0
  81. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/embeddings_client.py +0 -0
  82. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/graph_embeddings_client.py +0 -0
  83. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/graph_rag_client.py +0 -0
  84. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/llm_client.py +0 -0
  85. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/prompt_client.py +0 -0
  86. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/row_embeddings_client.py +0 -0
  87. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/clients/triples_query_client.py +0 -0
  88. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/exceptions.py +0 -0
  89. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/knowledge/__init__.py +0 -0
  90. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/knowledge/defs.py +0 -0
  91. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/knowledge/document.py +0 -0
  92. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/knowledge/identifier.py +0 -0
  93. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/knowledge/organization.py +0 -0
  94. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/knowledge/publication.py +0 -0
  95. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/log_level.py +0 -0
  96. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/__init__.py +0 -0
  97. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/registry.py +0 -0
  98. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/__init__.py +0 -0
  99. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/agent.py +0 -0
  100. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/base.py +0 -0
  101. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/collection.py +0 -0
  102. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/config.py +0 -0
  103. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/diagnosis.py +0 -0
  104. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/document_loading.py +0 -0
  105. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/embeddings.py +0 -0
  106. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/embeddings_query.py +0 -0
  107. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/flow.py +0 -0
  108. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/knowledge.py +0 -0
  109. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/library.py +0 -0
  110. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/metadata.py +0 -0
  111. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/nlp_query.py +0 -0
  112. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/primitives.py +0 -0
  113. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/prompt.py +0 -0
  114. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/retrieval.py +0 -0
  115. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/rows_query.py +0 -0
  116. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/structured_query.py +0 -0
  117. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/text_completion.py +0 -0
  118. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/tool.py +0 -0
  119. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/messaging/translators/triples.py +0 -0
  120. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/objects/__init__.py +0 -0
  121. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/objects/field.py +0 -0
  122. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/objects/object.py +0 -0
  123. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/provenance/uris.py +0 -0
  124. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/provenance/vocabulary.py +0 -0
  125. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/rdf.py +0 -0
  126. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/__init__.py +0 -0
  127. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/core/__init__.py +0 -0
  128. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/core/metadata.py +0 -0
  129. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/core/primitives.py +0 -0
  130. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/core/topic.py +0 -0
  131. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/__init__.py +0 -0
  132. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/document.py +0 -0
  133. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/embeddings.py +0 -0
  134. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/graph.py +0 -0
  135. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/knowledge.py +0 -0
  136. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/nlp.py +0 -0
  137. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/object.py +0 -0
  138. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/rows.py +0 -0
  139. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/knowledge/structured.py +0 -0
  140. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/__init__.py +0 -0
  141. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/agent.py +0 -0
  142. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/collection.py +0 -0
  143. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/config.py +0 -0
  144. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/diagnosis.py +0 -0
  145. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/flow.py +0 -0
  146. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/library.py +0 -0
  147. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/llm.py +0 -0
  148. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/lookup.py +0 -0
  149. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/nlp_query.py +0 -0
  150. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/prompt.py +0 -0
  151. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/query.py +0 -0
  152. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/rows_query.py +0 -0
  153. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/storage.py +0 -0
  154. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/structured_query.py +0 -0
  155. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph/schema/services/tool_service.py +0 -0
  156. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph_base.egg-info/SOURCES.txt +0 -0
  157. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph_base.egg-info/dependency_links.txt +0 -0
  158. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph_base.egg-info/requires.txt +0 -0
  159. {trustgraph_base-2.2.12 → trustgraph_base-2.2.14}/trustgraph_base.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trustgraph-base
3
- Version: 2.2.12
3
+ Version: 2.2.14
4
4
  Summary: TrustGraph provides a means to run a pipeline of flexible AI processing components in a flexible means to achieve a processing pipeline.
5
5
  Author-email: "trustgraph.ai" <security@trustgraph.ai>
6
6
  Project-URL: Homepage, https://github.com/trustgraph-ai/trustgraph
@@ -81,6 +81,7 @@ from .explainability import (
81
81
  Synthesis,
82
82
  Reflection,
83
83
  Analysis,
84
+ Observation,
84
85
  Conclusion,
85
86
  Decomposition,
86
87
  Finding,
@@ -164,6 +165,7 @@ __all__ = [
164
165
  "Focus",
165
166
  "Synthesis",
166
167
  "Analysis",
168
+ "Observation",
167
169
  "Conclusion",
168
170
  "EdgeSelection",
169
171
  "wire_triples_to_tuples",
@@ -40,6 +40,7 @@ TG_ANSWER_TYPE = TG + "Answer"
40
40
  TG_REFLECTION_TYPE = TG + "Reflection"
41
41
  TG_THOUGHT_TYPE = TG + "Thought"
42
42
  TG_OBSERVATION_TYPE = TG + "Observation"
43
+ TG_TOOL_USE = TG + "ToolUse"
43
44
  TG_GRAPH_RAG_QUESTION = TG + "GraphRagQuestion"
44
45
  TG_DOC_RAG_QUESTION = TG + "DocRagQuestion"
45
46
  TG_AGENT_QUESTION = TG + "AgentQuestion"
@@ -58,7 +59,6 @@ TG_PLAN_STEP = TG + "planStep"
58
59
  PROV = "http://www.w3.org/ns/prov#"
59
60
  PROV_STARTED_AT_TIME = PROV + "startedAtTime"
60
61
  PROV_WAS_DERIVED_FROM = PROV + "wasDerivedFrom"
61
- PROV_WAS_GENERATED_BY = PROV + "wasGeneratedBy"
62
62
 
63
63
  RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
64
64
  RDFS_LABEL = "http://www.w3.org/2000/01/rdf-schema#label"
@@ -102,6 +102,8 @@ class ExplainEntity:
102
102
  return StepResult.from_triples(uri, triples)
103
103
  elif TG_SYNTHESIS in types:
104
104
  return Synthesis.from_triples(uri, triples)
105
+ elif TG_OBSERVATION_TYPE in types and TG_REFLECTION_TYPE not in types:
106
+ return Observation.from_triples(uri, triples)
105
107
  elif TG_REFLECTION_TYPE in types:
106
108
  return Reflection.from_triples(uri, triples)
107
109
  elif TG_ANALYSIS in types:
@@ -279,18 +281,16 @@ class Reflection(ExplainEntity):
279
281
 
280
282
  @dataclass
281
283
  class Analysis(ExplainEntity):
282
- """Analysis entity - one think/act/observe cycle (Agent only)."""
284
+ """Analysis+ToolUse entity - decision + tool call (Agent only)."""
283
285
  action: str = ""
284
286
  arguments: str = "" # JSON string
285
287
  thought: str = ""
286
- observation: str = ""
287
288
 
288
289
  @classmethod
289
290
  def from_triples(cls, uri: str, triples: List[Tuple[str, str, Any]]) -> "Analysis":
290
291
  action = ""
291
292
  arguments = ""
292
293
  thought = ""
293
- observation = ""
294
294
 
295
295
  for s, p, o in triples:
296
296
  if p == TG_ACTION:
@@ -299,8 +299,6 @@ class Analysis(ExplainEntity):
299
299
  arguments = o
300
300
  elif p == TG_THOUGHT:
301
301
  thought = o
302
- elif p == TG_OBSERVATION:
303
- observation = o
304
302
 
305
303
  return cls(
306
304
  uri=uri,
@@ -308,7 +306,26 @@ class Analysis(ExplainEntity):
308
306
  action=action,
309
307
  arguments=arguments,
310
308
  thought=thought,
311
- observation=observation
309
+ )
310
+
311
+
312
+ @dataclass
313
+ class Observation(ExplainEntity):
314
+ """Observation entity - standalone tool result (Agent only)."""
315
+ document: str = ""
316
+
317
+ @classmethod
318
+ def from_triples(cls, uri: str, triples: List[Tuple[str, str, Any]]) -> "Observation":
319
+ document = ""
320
+
321
+ for s, p, o in triples:
322
+ if p == TG_DOCUMENT:
323
+ document = o
324
+
325
+ return cls(
326
+ uri=uri,
327
+ entity_type="observation",
328
+ document=document,
312
329
  )
313
330
 
314
331
 
@@ -757,9 +774,9 @@ class ExplainabilityClient:
757
774
  return trace
758
775
  trace["question"] = question
759
776
 
760
- # Find grounding: ?grounding prov:wasGeneratedBy question_uri
777
+ # Find grounding: ?grounding prov:wasDerivedFrom question_uri
761
778
  grounding_triples = self.flow.triples_query(
762
- p=PROV_WAS_GENERATED_BY,
779
+ p=PROV_WAS_DERIVED_FROM,
763
780
  o=question_uri,
764
781
  g=graph,
765
782
  user=user,
@@ -894,9 +911,9 @@ class ExplainabilityClient:
894
911
  return trace
895
912
  trace["question"] = question
896
913
 
897
- # Find grounding: ?grounding prov:wasGeneratedBy question_uri
914
+ # Find grounding: ?grounding prov:wasDerivedFrom question_uri
898
915
  grounding_triples = self.flow.triples_query(
899
- p=PROV_WAS_GENERATED_BY,
916
+ p=PROV_WAS_DERIVED_FROM,
900
917
  o=question_uri,
901
918
  g=graph,
902
919
  user=user,
@@ -1010,41 +1027,26 @@ class ExplainabilityClient:
1010
1027
  # Follow the provenance chain from the question
1011
1028
  self._follow_provenance_chain(
1012
1029
  session_uri, trace, graph, user, collection,
1013
- is_first=True, max_depth=50,
1030
+ max_depth=50,
1014
1031
  )
1015
1032
 
1016
1033
  return trace
1017
1034
 
1018
1035
  def _follow_provenance_chain(
1019
1036
  self, current_uri, trace, graph, user, collection,
1020
- is_first=False, max_depth=50,
1037
+ max_depth=50,
1021
1038
  ):
1022
1039
  """Recursively follow the provenance chain, handling branches."""
1023
1040
  if max_depth <= 0:
1024
1041
  return
1025
1042
 
1026
1043
  # Find entities derived from current_uri
1027
- if is_first:
1028
- derived_triples = self.flow.triples_query(
1029
- p=PROV_WAS_GENERATED_BY,
1030
- o=current_uri,
1031
- g=graph, user=user, collection=collection,
1032
- limit=20
1033
- )
1034
- if not derived_triples:
1035
- derived_triples = self.flow.triples_query(
1036
- p=PROV_WAS_DERIVED_FROM,
1037
- o=current_uri,
1038
- g=graph, user=user, collection=collection,
1039
- limit=20
1040
- )
1041
- else:
1042
- derived_triples = self.flow.triples_query(
1043
- p=PROV_WAS_DERIVED_FROM,
1044
- o=current_uri,
1045
- g=graph, user=user, collection=collection,
1046
- limit=20
1047
- )
1044
+ derived_triples = self.flow.triples_query(
1045
+ p=PROV_WAS_DERIVED_FROM,
1046
+ o=current_uri,
1047
+ g=graph, user=user, collection=collection,
1048
+ limit=20
1049
+ )
1048
1050
 
1049
1051
  if not derived_triples:
1050
1052
  return
@@ -1062,8 +1064,8 @@ class ExplainabilityClient:
1062
1064
  if entity is None:
1063
1065
  continue
1064
1066
 
1065
- if isinstance(entity, (Analysis, Decomposition, Finding,
1066
- Plan, StepResult)):
1067
+ if isinstance(entity, (Analysis, Observation, Decomposition,
1068
+ Finding, Plan, StepResult)):
1067
1069
  trace["steps"].append(entity)
1068
1070
 
1069
1071
  # Continue following from this entity
@@ -1072,6 +1074,36 @@ class ExplainabilityClient:
1072
1074
  max_depth=max_depth - 1,
1073
1075
  )
1074
1076
 
1077
+ elif isinstance(entity, Question):
1078
+ # Sub-trace: a RAG session linked to this agent step.
1079
+ # Fetch the full sub-trace and embed it.
1080
+ if entity.question_type == "graph-rag":
1081
+ sub_trace = self.fetch_graphrag_trace(
1082
+ derived_uri, graph, user, collection,
1083
+ )
1084
+ elif entity.question_type == "document-rag":
1085
+ sub_trace = self.fetch_docrag_trace(
1086
+ derived_uri, graph, user, collection,
1087
+ )
1088
+ else:
1089
+ sub_trace = None
1090
+
1091
+ if sub_trace:
1092
+ trace["steps"].append({
1093
+ "type": "sub-trace",
1094
+ "question": entity,
1095
+ "trace": sub_trace,
1096
+ })
1097
+
1098
+ # Continue from the sub-trace's terminal entity
1099
+ # (Observation may derive from Synthesis)
1100
+ terminal = sub_trace.get("synthesis")
1101
+ if terminal:
1102
+ self._follow_provenance_chain(
1103
+ terminal.uri, trace, graph, user, collection,
1104
+ max_depth=max_depth - 1,
1105
+ )
1106
+
1075
1107
  elif isinstance(entity, (Conclusion, Synthesis)):
1076
1108
  trace["steps"].append(entity)
1077
1109
 
@@ -1114,10 +1146,25 @@ class ExplainabilityClient:
1114
1146
  if isinstance(entity, Question):
1115
1147
  questions.append(entity)
1116
1148
 
1149
+ # Filter out sub-traces: sessions that have a wasDerivedFrom link
1150
+ # (they are child sessions linked to a parent agent iteration)
1151
+ top_level = []
1152
+ for q in questions:
1153
+ parent_triples = self.flow.triples_query(
1154
+ s=q.uri,
1155
+ p=PROV_WAS_DERIVED_FROM,
1156
+ g=graph,
1157
+ user=user,
1158
+ collection=collection,
1159
+ limit=1
1160
+ )
1161
+ if not parent_triples:
1162
+ top_level.append(q)
1163
+
1117
1164
  # Sort by timestamp (newest first)
1118
- questions.sort(key=lambda q: q.timestamp or "", reverse=True)
1165
+ top_level.sort(key=lambda q: q.timestamp or "", reverse=True)
1119
1166
 
1120
- return questions
1167
+ return top_level
1121
1168
 
1122
1169
  def detect_session_type(
1123
1170
  self,
@@ -1159,18 +1206,9 @@ class ExplainabilityClient:
1159
1206
  limit=5
1160
1207
  )
1161
1208
 
1162
- generated_triples = self.flow.triples_query(
1163
- p=PROV_WAS_GENERATED_BY,
1164
- o=session_uri,
1165
- g=graph,
1166
- user=user,
1167
- collection=collection,
1168
- limit=5
1169
- )
1170
-
1171
1209
  all_child_uris = [
1172
1210
  extract_term_value(t.get("s", {}))
1173
- for t in (derived_triples + generated_triples)
1211
+ for t in derived_triples
1174
1212
  ]
1175
1213
 
1176
1214
  for child_uri in all_child_uris:
@@ -384,18 +384,21 @@ class SocketClient:
384
384
  if chunk_type == "thought":
385
385
  return AgentThought(
386
386
  content=resp.get("content", ""),
387
- end_of_message=resp.get("end_of_message", False)
387
+ end_of_message=resp.get("end_of_message", False),
388
+ message_id=resp.get("message_id", ""),
388
389
  )
389
390
  elif chunk_type == "observation":
390
391
  return AgentObservation(
391
392
  content=resp.get("content", ""),
392
- end_of_message=resp.get("end_of_message", False)
393
+ end_of_message=resp.get("end_of_message", False),
394
+ message_id=resp.get("message_id", ""),
393
395
  )
394
396
  elif chunk_type == "answer" or chunk_type == "final-answer":
395
397
  return AgentAnswer(
396
398
  content=resp.get("content", ""),
397
399
  end_of_message=resp.get("end_of_message", False),
398
- end_of_dialog=resp.get("end_of_dialog", False)
400
+ end_of_dialog=resp.get("end_of_dialog", False),
401
+ message_id=resp.get("message_id", ""),
399
402
  )
400
403
  elif chunk_type == "action":
401
404
  return AgentThought(
@@ -150,8 +150,10 @@ class AgentThought(StreamingChunk):
150
150
  content: Agent's thought text
151
151
  end_of_message: True if this completes the current thought
152
152
  chunk_type: Always "thought"
153
+ message_id: Provenance URI of the entity being built
153
154
  """
154
155
  chunk_type: str = "thought"
156
+ message_id: str = ""
155
157
 
156
158
  @dataclasses.dataclass
157
159
  class AgentObservation(StreamingChunk):
@@ -165,8 +167,10 @@ class AgentObservation(StreamingChunk):
165
167
  content: Observation text describing tool results
166
168
  end_of_message: True if this completes the current observation
167
169
  chunk_type: Always "observation"
170
+ message_id: Provenance URI of the entity being built
168
171
  """
169
172
  chunk_type: str = "observation"
173
+ message_id: str = ""
170
174
 
171
175
  @dataclasses.dataclass
172
176
  class AgentAnswer(StreamingChunk):
@@ -184,6 +188,7 @@ class AgentAnswer(StreamingChunk):
184
188
  """
185
189
  chunk_type: str = "final-answer"
186
190
  end_of_dialog: bool = False
191
+ message_id: str = ""
187
192
 
188
193
  @dataclasses.dataclass
189
194
  class RAGChunk(StreamingChunk):
@@ -5,6 +5,7 @@ from .. schema import GraphRagQuery, GraphRagResponse
5
5
  class GraphRagClient(RequestResponse):
6
6
  async def rag(self, query, user="trustgraph", collection="default",
7
7
  chunk_callback=None, explain_callback=None,
8
+ parent_uri="",
8
9
  timeout=600):
9
10
  """
10
11
  Execute a graph RAG query with optional streaming callbacks.
@@ -50,6 +51,7 @@ class GraphRagClient(RequestResponse):
50
51
  query = query,
51
52
  user = user,
52
53
  collection = collection,
54
+ parent_uri = parent_uri,
53
55
  ),
54
56
  timeout=timeout,
55
57
  recipient=recipient,
@@ -0,0 +1 @@
1
+ __version__ = "2.2.14"
@@ -96,6 +96,7 @@ from . namespaces import (
96
96
  TG_ANALYSIS, TG_CONCLUSION,
97
97
  # Unifying types
98
98
  TG_ANSWER_TYPE, TG_REFLECTION_TYPE, TG_THOUGHT_TYPE, TG_OBSERVATION_TYPE,
99
+ TG_TOOL_USE,
99
100
  # Question subtypes (to distinguish retrieval mechanism)
100
101
  TG_GRAPH_RAG_QUESTION, TG_DOC_RAG_QUESTION, TG_AGENT_QUESTION,
101
102
  # Agent provenance predicates
@@ -132,6 +133,7 @@ from . triples import (
132
133
  from . agent import (
133
134
  agent_session_triples,
134
135
  agent_iteration_triples,
136
+ agent_observation_triples,
135
137
  agent_final_triples,
136
138
  # Orchestrator provenance triple builders
137
139
  agent_decomposition_triples,
@@ -210,6 +212,7 @@ __all__ = [
210
212
  "TG_ANALYSIS", "TG_CONCLUSION",
211
213
  # Unifying types
212
214
  "TG_ANSWER_TYPE", "TG_REFLECTION_TYPE", "TG_THOUGHT_TYPE", "TG_OBSERVATION_TYPE",
215
+ "TG_TOOL_USE",
213
216
  # Question subtypes
214
217
  "TG_GRAPH_RAG_QUESTION", "TG_DOC_RAG_QUESTION", "TG_AGENT_QUESTION",
215
218
  # Agent provenance predicates
@@ -238,6 +241,7 @@ __all__ = [
238
241
  # Agent provenance triple builders
239
242
  "agent_session_triples",
240
243
  "agent_iteration_triples",
244
+ "agent_observation_triples",
241
245
  "agent_final_triples",
242
246
  # Orchestrator provenance triple builders
243
247
  "agent_decomposition_triples",
@@ -20,11 +20,12 @@ from .. schema import Triple, Term, IRI, LITERAL
20
20
 
21
21
  from . namespaces import (
22
22
  RDF_TYPE, RDFS_LABEL,
23
- PROV_ACTIVITY, PROV_ENTITY, PROV_WAS_DERIVED_FROM,
24
- PROV_WAS_GENERATED_BY, PROV_STARTED_AT_TIME,
25
- TG_QUERY, TG_THOUGHT, TG_ACTION, TG_ARGUMENTS, TG_OBSERVATION,
23
+ PROV_ENTITY, PROV_WAS_DERIVED_FROM,
24
+ PROV_STARTED_AT_TIME,
25
+ TG_QUERY, TG_THOUGHT, TG_ACTION, TG_ARGUMENTS,
26
26
  TG_QUESTION, TG_ANALYSIS, TG_CONCLUSION, TG_DOCUMENT,
27
27
  TG_ANSWER_TYPE, TG_REFLECTION_TYPE, TG_THOUGHT_TYPE, TG_OBSERVATION_TYPE,
28
+ TG_TOOL_USE,
28
29
  TG_AGENT_QUESTION,
29
30
  TG_DECOMPOSITION, TG_FINDING, TG_PLAN_TYPE, TG_STEP_RESULT,
30
31
  TG_SYNTHESIS, TG_SUBAGENT_GOAL, TG_PLAN_STEP,
@@ -50,6 +51,7 @@ def agent_session_triples(
50
51
  session_uri: str,
51
52
  query: str,
52
53
  timestamp: Optional[str] = None,
54
+ parent_uri: Optional[str] = None,
53
55
  ) -> List[Triple]:
54
56
  """
55
57
  Build triples for an agent session start (Question).
@@ -57,11 +59,13 @@ def agent_session_triples(
57
59
  Creates:
58
60
  - Activity declaration with tg:Question type
59
61
  - Query text and timestamp
62
+ - wasDerivedFrom link to parent (for subagent sessions)
60
63
 
61
64
  Args:
62
65
  session_uri: URI of the session (from agent_session_uri)
63
66
  query: The user's query text
64
67
  timestamp: ISO timestamp (defaults to now)
68
+ parent_uri: URI of the parent entity (e.g. Decomposition) for subagents
65
69
 
66
70
  Returns:
67
71
  List of Triple objects
@@ -69,8 +73,8 @@ def agent_session_triples(
69
73
  if timestamp is None:
70
74
  timestamp = datetime.utcnow().isoformat() + "Z"
71
75
 
72
- return [
73
- _triple(session_uri, RDF_TYPE, _iri(PROV_ACTIVITY)),
76
+ triples = [
77
+ _triple(session_uri, RDF_TYPE, _iri(PROV_ENTITY)),
74
78
  _triple(session_uri, RDF_TYPE, _iri(TG_QUESTION)),
75
79
  _triple(session_uri, RDF_TYPE, _iri(TG_AGENT_QUESTION)),
76
80
  _triple(session_uri, RDFS_LABEL, _literal("Agent Question")),
@@ -78,6 +82,13 @@ def agent_session_triples(
78
82
  _triple(session_uri, TG_QUERY, _literal(query)),
79
83
  ]
80
84
 
85
+ if parent_uri:
86
+ triples.append(
87
+ _triple(session_uri, PROV_WAS_DERIVED_FROM, _iri(parent_uri))
88
+ )
89
+
90
+ return triples
91
+
81
92
 
82
93
  def agent_iteration_triples(
83
94
  iteration_uri: str,
@@ -87,19 +98,15 @@ def agent_iteration_triples(
87
98
  arguments: Dict[str, Any] = None,
88
99
  thought_uri: Optional[str] = None,
89
100
  thought_document_id: Optional[str] = None,
90
- observation_uri: Optional[str] = None,
91
- observation_document_id: Optional[str] = None,
92
101
  ) -> List[Triple]:
93
102
  """
94
- Build triples for one agent iteration (Analysis - think/act/observe cycle).
103
+ Build triples for one agent iteration (Analysis+ToolUse).
95
104
 
96
105
  Creates:
97
- - Entity declaration with tg:Analysis type
98
- - wasGeneratedBy link to question (if first iteration)
99
- - wasDerivedFrom link to previous iteration (if not first)
106
+ - Entity declaration with tg:Analysis and tg:ToolUse types
107
+ - wasDerivedFrom link to question (if first iteration) or previous
100
108
  - Action and arguments metadata
101
109
  - Thought sub-entity (tg:Reflection, tg:Thought) with librarian document
102
- - Observation sub-entity (tg:Reflection, tg:Observation) with librarian document
103
110
 
104
111
  Args:
105
112
  iteration_uri: URI of this iteration (from agent_iteration_uri)
@@ -109,8 +116,6 @@ def agent_iteration_triples(
109
116
  arguments: Arguments passed to the tool (will be JSON-encoded)
110
117
  thought_uri: URI for the thought sub-entity
111
118
  thought_document_id: Document URI for thought in librarian
112
- observation_uri: URI for the observation sub-entity
113
- observation_document_id: Document URI for observation in librarian
114
119
 
115
120
  Returns:
116
121
  List of Triple objects
@@ -121,6 +126,7 @@ def agent_iteration_triples(
121
126
  triples = [
122
127
  _triple(iteration_uri, RDF_TYPE, _iri(PROV_ENTITY)),
123
128
  _triple(iteration_uri, RDF_TYPE, _iri(TG_ANALYSIS)),
129
+ _triple(iteration_uri, RDF_TYPE, _iri(TG_TOOL_USE)),
124
130
  _triple(iteration_uri, RDFS_LABEL, _literal(f"Analysis: {action}")),
125
131
  _triple(iteration_uri, TG_ACTION, _literal(action)),
126
132
  _triple(iteration_uri, TG_ARGUMENTS, _literal(json.dumps(arguments))),
@@ -128,7 +134,7 @@ def agent_iteration_triples(
128
134
 
129
135
  if question_uri:
130
136
  triples.append(
131
- _triple(iteration_uri, PROV_WAS_GENERATED_BY, _iri(question_uri))
137
+ _triple(iteration_uri, PROV_WAS_DERIVED_FROM, _iri(question_uri))
132
138
  )
133
139
  elif previous_uri:
134
140
  triples.append(
@@ -142,26 +148,48 @@ def agent_iteration_triples(
142
148
  _triple(thought_uri, RDF_TYPE, _iri(TG_REFLECTION_TYPE)),
143
149
  _triple(thought_uri, RDF_TYPE, _iri(TG_THOUGHT_TYPE)),
144
150
  _triple(thought_uri, RDFS_LABEL, _literal("Thought")),
145
- _triple(thought_uri, PROV_WAS_GENERATED_BY, _iri(iteration_uri)),
151
+ _triple(thought_uri, PROV_WAS_DERIVED_FROM, _iri(iteration_uri)),
146
152
  ])
147
153
  if thought_document_id:
148
154
  triples.append(
149
155
  _triple(thought_uri, TG_DOCUMENT, _iri(thought_document_id))
150
156
  )
151
157
 
152
- # Observation sub-entity
153
- if observation_uri:
154
- triples.extend([
155
- _triple(iteration_uri, TG_OBSERVATION, _iri(observation_uri)),
156
- _triple(observation_uri, RDF_TYPE, _iri(TG_REFLECTION_TYPE)),
157
- _triple(observation_uri, RDF_TYPE, _iri(TG_OBSERVATION_TYPE)),
158
- _triple(observation_uri, RDFS_LABEL, _literal("Observation")),
159
- _triple(observation_uri, PROV_WAS_GENERATED_BY, _iri(iteration_uri)),
160
- ])
161
- if observation_document_id:
162
- triples.append(
163
- _triple(observation_uri, TG_DOCUMENT, _iri(observation_document_id))
164
- )
158
+ return triples
159
+
160
+
161
+ def agent_observation_triples(
162
+ observation_uri: str,
163
+ iteration_uri: str,
164
+ document_id: Optional[str] = None,
165
+ ) -> List[Triple]:
166
+ """
167
+ Build triples for an agent observation (standalone entity).
168
+
169
+ Creates:
170
+ - Entity declaration with prov:Entity and tg:Observation types
171
+ - wasDerivedFrom link to the iteration (Analysis+ToolUse)
172
+ - Document reference to librarian (if provided)
173
+
174
+ Args:
175
+ observation_uri: URI of the observation entity
176
+ iteration_uri: URI of the iteration this observation derives from
177
+ document_id: Librarian document ID for the observation content
178
+
179
+ Returns:
180
+ List of Triple objects
181
+ """
182
+ triples = [
183
+ _triple(observation_uri, RDF_TYPE, _iri(PROV_ENTITY)),
184
+ _triple(observation_uri, RDF_TYPE, _iri(TG_OBSERVATION_TYPE)),
185
+ _triple(observation_uri, RDFS_LABEL, _literal("Observation")),
186
+ _triple(observation_uri, PROV_WAS_DERIVED_FROM, _iri(iteration_uri)),
187
+ ]
188
+
189
+ if document_id:
190
+ triples.append(
191
+ _triple(observation_uri, TG_DOCUMENT, _iri(document_id))
192
+ )
165
193
 
166
194
  return triples
167
195
 
@@ -199,7 +227,7 @@ def agent_final_triples(
199
227
 
200
228
  if question_uri:
201
229
  triples.append(
202
- _triple(final_uri, PROV_WAS_GENERATED_BY, _iri(question_uri))
230
+ _triple(final_uri, PROV_WAS_DERIVED_FROM, _iri(question_uri))
203
231
  )
204
232
  elif previous_uri:
205
233
  triples.append(
@@ -223,7 +251,7 @@ def agent_decomposition_triples(
223
251
  _triple(uri, RDF_TYPE, _iri(TG_DECOMPOSITION)),
224
252
  _triple(uri, RDFS_LABEL,
225
253
  _literal(f"Decomposed into {len(goals)} research threads")),
226
- _triple(uri, PROV_WAS_GENERATED_BY, _iri(session_uri)),
254
+ _triple(uri, PROV_WAS_DERIVED_FROM, _iri(session_uri)),
227
255
  ]
228
256
  for goal in goals:
229
257
  triples.append(_triple(uri, TG_SUBAGENT_GOAL, _literal(goal)))
@@ -261,7 +289,7 @@ def agent_plan_triples(
261
289
  _triple(uri, RDF_TYPE, _iri(TG_PLAN_TYPE)),
262
290
  _triple(uri, RDFS_LABEL,
263
291
  _literal(f"Plan with {len(steps)} steps")),
264
- _triple(uri, PROV_WAS_GENERATED_BY, _iri(session_uri)),
292
+ _triple(uri, PROV_WAS_DERIVED_FROM, _iri(session_uri)),
265
293
  ]
266
294
  for step in steps:
267
295
  triples.append(_triple(uri, TG_PLAN_STEP, _literal(step)))
@@ -290,17 +318,28 @@ def agent_step_result_triples(
290
318
 
291
319
  def agent_synthesis_triples(
292
320
  uri: str,
293
- previous_uri: str,
321
+ previous_uris,
294
322
  document_id: Optional[str] = None,
295
323
  ) -> List[Triple]:
296
- """Build triples for a synthesis answer."""
324
+ """Build triples for a synthesis answer.
325
+
326
+ Args:
327
+ uri: URI of the synthesis entity
328
+ previous_uris: Single URI string or list of URIs to derive from
329
+ document_id: Librarian document ID for the answer content
330
+ """
297
331
  triples = [
298
332
  _triple(uri, RDF_TYPE, _iri(PROV_ENTITY)),
299
333
  _triple(uri, RDF_TYPE, _iri(TG_SYNTHESIS)),
300
334
  _triple(uri, RDF_TYPE, _iri(TG_ANSWER_TYPE)),
301
335
  _triple(uri, RDFS_LABEL, _literal("Synthesis")),
302
- _triple(uri, PROV_WAS_DERIVED_FROM, _iri(previous_uri)),
303
336
  ]
337
+
338
+ if isinstance(previous_uris, str):
339
+ previous_uris = [previous_uris]
340
+ for prev in previous_uris:
341
+ triples.append(_triple(uri, PROV_WAS_DERIVED_FROM, _iri(prev)))
342
+
304
343
  if document_id:
305
344
  triples.append(_triple(uri, TG_DOCUMENT, _iri(document_id)))
306
345
  return triples
@@ -105,6 +105,7 @@ TG_ANSWER_TYPE = TG + "Answer" # Final answer (Synthesis, Conclusion, F
105
105
  TG_REFLECTION_TYPE = TG + "Reflection" # Intermediate commentary (Thought, Observation)
106
106
  TG_THOUGHT_TYPE = TG + "Thought" # Agent reasoning
107
107
  TG_OBSERVATION_TYPE = TG + "Observation" # Agent tool result
108
+ TG_TOOL_USE = TG + "ToolUse" # Analysis+ToolUse mixin
108
109
 
109
110
  # Question subtypes (to distinguish retrieval mechanism)
110
111
  TG_GRAPH_RAG_QUESTION = TG + "GraphRagQuestion"