trustgraph-base 2.2.20__tar.gz → 2.2.22__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 (164) hide show
  1. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/PKG-INFO +1 -1
  2. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/socket_client.py +38 -8
  3. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/types.py +24 -2
  4. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/async_processor.py +2 -2
  5. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/consumer.py +47 -23
  6. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/rabbitmq_backend.py +1 -0
  7. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/subscriber.py +30 -16
  8. trustgraph_base-2.2.22/trustgraph/base_version.py +1 -0
  9. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/agent.py +13 -2
  10. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/collection.py +0 -3
  11. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/retrieval.py +21 -0
  12. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/agent.py +4 -3
  13. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/retrieval.py +8 -6
  14. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph_base.egg-info/PKG-INFO +1 -1
  15. trustgraph_base-2.2.20/trustgraph/base_version.py +0 -1
  16. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/README.md +0 -0
  17. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/pyproject.toml +0 -0
  18. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/setup.cfg +0 -0
  19. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/__init__.py +0 -0
  20. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/api.py +0 -0
  21. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/async_bulk_client.py +0 -0
  22. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/async_flow.py +0 -0
  23. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/async_metrics.py +0 -0
  24. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/async_socket_client.py +0 -0
  25. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/bulk_client.py +0 -0
  26. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/collection.py +0 -0
  27. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/config.py +0 -0
  28. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/exceptions.py +0 -0
  29. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/explainability.py +0 -0
  30. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/flow.py +0 -0
  31. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/knowledge.py +0 -0
  32. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/library.py +0 -0
  33. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/api/metrics.py +0 -0
  34. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/__init__.py +0 -0
  35. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/agent_client.py +0 -0
  36. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/agent_service.py +0 -0
  37. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/backend.py +0 -0
  38. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/cassandra_config.py +0 -0
  39. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/chunking_service.py +0 -0
  40. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/collection_config_handler.py +0 -0
  41. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/consumer_spec.py +0 -0
  42. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/document_embeddings_client.py +0 -0
  43. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/document_embeddings_query_service.py +0 -0
  44. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/document_embeddings_store_service.py +0 -0
  45. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/dynamic_tool_service.py +0 -0
  46. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/embeddings_client.py +0 -0
  47. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/embeddings_service.py +0 -0
  48. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/flow.py +0 -0
  49. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/flow_processor.py +0 -0
  50. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/graph_embeddings_client.py +0 -0
  51. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/graph_embeddings_query_service.py +0 -0
  52. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/graph_embeddings_store_service.py +0 -0
  53. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/graph_rag_client.py +0 -0
  54. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/librarian_client.py +0 -0
  55. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/llm_service.py +0 -0
  56. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/logging.py +0 -0
  57. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/metrics.py +0 -0
  58. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/parameter_spec.py +0 -0
  59. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/producer.py +0 -0
  60. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/producer_spec.py +0 -0
  61. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/prompt_client.py +0 -0
  62. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/publisher.py +0 -0
  63. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/pubsub.py +0 -0
  64. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/pulsar_backend.py +0 -0
  65. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/request_response_spec.py +0 -0
  66. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/row_embeddings_query_client.py +0 -0
  67. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/serialization.py +0 -0
  68. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/spec.py +0 -0
  69. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/structured_query_client.py +0 -0
  70. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/subscriber_spec.py +0 -0
  71. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/text_completion_client.py +0 -0
  72. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/tool_client.py +0 -0
  73. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/tool_service.py +0 -0
  74. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/tool_service_client.py +0 -0
  75. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/triples_client.py +0 -0
  76. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/triples_query_service.py +0 -0
  77. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/base/triples_store_service.py +0 -0
  78. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/__init__.py +0 -0
  79. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/agent_client.py +0 -0
  80. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/base.py +0 -0
  81. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/config_client.py +0 -0
  82. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/document_embeddings_client.py +0 -0
  83. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/document_rag_client.py +0 -0
  84. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/embeddings_client.py +0 -0
  85. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/graph_embeddings_client.py +0 -0
  86. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/graph_rag_client.py +0 -0
  87. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/llm_client.py +0 -0
  88. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/prompt_client.py +0 -0
  89. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/row_embeddings_client.py +0 -0
  90. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/clients/triples_query_client.py +0 -0
  91. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/exceptions.py +0 -0
  92. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/knowledge/__init__.py +0 -0
  93. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/knowledge/defs.py +0 -0
  94. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/knowledge/document.py +0 -0
  95. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/knowledge/identifier.py +0 -0
  96. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/knowledge/organization.py +0 -0
  97. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/knowledge/publication.py +0 -0
  98. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/log_level.py +0 -0
  99. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/__init__.py +0 -0
  100. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/registry.py +0 -0
  101. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/__init__.py +0 -0
  102. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/base.py +0 -0
  103. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/config.py +0 -0
  104. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/diagnosis.py +0 -0
  105. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/document_loading.py +0 -0
  106. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/embeddings.py +0 -0
  107. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/embeddings_query.py +0 -0
  108. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/flow.py +0 -0
  109. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/knowledge.py +0 -0
  110. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/library.py +0 -0
  111. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/metadata.py +0 -0
  112. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/nlp_query.py +0 -0
  113. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/primitives.py +0 -0
  114. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/prompt.py +0 -0
  115. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/rows_query.py +0 -0
  116. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/sparql_query.py +0 -0
  117. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/structured_query.py +0 -0
  118. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/text_completion.py +0 -0
  119. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/tool.py +0 -0
  120. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/messaging/translators/triples.py +0 -0
  121. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/objects/__init__.py +0 -0
  122. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/objects/field.py +0 -0
  123. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/objects/object.py +0 -0
  124. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/provenance/__init__.py +0 -0
  125. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/provenance/agent.py +0 -0
  126. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/provenance/namespaces.py +0 -0
  127. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/provenance/triples.py +0 -0
  128. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/provenance/uris.py +0 -0
  129. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/provenance/vocabulary.py +0 -0
  130. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/rdf.py +0 -0
  131. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/__init__.py +0 -0
  132. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/core/__init__.py +0 -0
  133. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/core/metadata.py +0 -0
  134. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/core/primitives.py +0 -0
  135. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/core/topic.py +0 -0
  136. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/__init__.py +0 -0
  137. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/document.py +0 -0
  138. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/embeddings.py +0 -0
  139. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/graph.py +0 -0
  140. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/knowledge.py +0 -0
  141. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/nlp.py +0 -0
  142. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/object.py +0 -0
  143. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/rows.py +0 -0
  144. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/knowledge/structured.py +0 -0
  145. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/__init__.py +0 -0
  146. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/collection.py +0 -0
  147. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/config.py +0 -0
  148. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/diagnosis.py +0 -0
  149. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/flow.py +0 -0
  150. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/library.py +0 -0
  151. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/llm.py +0 -0
  152. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/lookup.py +0 -0
  153. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/nlp_query.py +0 -0
  154. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/prompt.py +0 -0
  155. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/query.py +0 -0
  156. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/rows_query.py +0 -0
  157. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/sparql_query.py +0 -0
  158. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/storage.py +0 -0
  159. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/structured_query.py +0 -0
  160. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph/schema/services/tool_service.py +0 -0
  161. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph_base.egg-info/SOURCES.txt +0 -0
  162. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph_base.egg-info/dependency_links.txt +0 -0
  163. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/trustgraph_base.egg-info/requires.txt +0 -0
  164. {trustgraph_base-2.2.20 → trustgraph_base-2.2.22}/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.20
3
+ Version: 2.2.22
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
@@ -366,19 +366,13 @@ class SocketClient:
366
366
  # Handle GraphRAG/DocRAG message format with message_type
367
367
  if message_type == "explain":
368
368
  if include_provenance:
369
- return ProvenanceEvent(
370
- explain_id=resp.get("explain_id", ""),
371
- explain_graph=resp.get("explain_graph", "")
372
- )
369
+ return self._build_provenance_event(resp)
373
370
  return None
374
371
 
375
372
  # Handle Agent message format with chunk_type="explain"
376
373
  if chunk_type == "explain":
377
374
  if include_provenance:
378
- return ProvenanceEvent(
379
- explain_id=resp.get("explain_id", ""),
380
- explain_graph=resp.get("explain_graph", "")
381
- )
375
+ return self._build_provenance_event(resp)
382
376
  return None
383
377
 
384
378
  if chunk_type == "thought":
@@ -413,6 +407,42 @@ class SocketClient:
413
407
  error=None
414
408
  )
415
409
 
410
+ def _build_provenance_event(self, resp: Dict[str, Any]) -> ProvenanceEvent:
411
+ """Build a ProvenanceEvent from a response dict, parsing inline triples
412
+ into an ExplainEntity if available."""
413
+ explain_id = resp.get("explain_id", "")
414
+ explain_graph = resp.get("explain_graph", "")
415
+ raw_triples = resp.get("explain_triples", [])
416
+
417
+ entity = None
418
+ if raw_triples:
419
+ try:
420
+ from .explainability import ExplainEntity
421
+ # Convert wire-format triple dicts to (s, p, o) tuples
422
+ parsed = []
423
+ for t in raw_triples:
424
+ s = t.get("s", {}).get("i", "") if t.get("s") else ""
425
+ p = t.get("p", {}).get("i", "") if t.get("p") else ""
426
+ o_term = t.get("o", {})
427
+ if o_term:
428
+ if o_term.get("t") == "i":
429
+ o = o_term.get("i", "")
430
+ else:
431
+ o = o_term.get("v", "")
432
+ else:
433
+ o = ""
434
+ parsed.append((s, p, o))
435
+ entity = ExplainEntity.from_triples(explain_id, parsed)
436
+ except Exception:
437
+ pass
438
+
439
+ return ProvenanceEvent(
440
+ explain_id=explain_id,
441
+ explain_graph=explain_graph,
442
+ entity=entity,
443
+ triples=raw_triples,
444
+ )
445
+
416
446
  def close(self) -> None:
417
447
  """Close the persistent WebSocket connection."""
418
448
  if self._loop and not self._loop.is_closed():
@@ -213,25 +213,47 @@ class ProvenanceEvent:
213
213
  """
214
214
  Provenance event for explainability.
215
215
 
216
- Emitted during GraphRAG queries when explainable mode is enabled.
216
+ Emitted during retrieval queries when explainable mode is enabled.
217
217
  Each event represents a provenance node created during query processing.
218
218
 
219
219
  Attributes:
220
220
  explain_id: URI of the provenance node (e.g., urn:trustgraph:question:abc123)
221
221
  explain_graph: Named graph where provenance triples are stored (e.g., urn:graph:retrieval)
222
- event_type: Type of provenance event (question, exploration, focus, synthesis)
222
+ event_type: Type of provenance event (question, exploration, focus, synthesis, etc.)
223
+ entity: Parsed ExplainEntity from inline triples (if available)
224
+ triples: Raw triples from the response (wire format dicts)
223
225
  """
224
226
  explain_id: str
225
227
  explain_graph: str = ""
226
228
  event_type: str = "" # Derived from explain_id
229
+ entity: object = None # ExplainEntity (parsed from triples)
230
+ triples: list = dataclasses.field(default_factory=list) # Raw wire-format triple dicts
227
231
 
228
232
  def __post_init__(self):
229
233
  # Extract event type from explain_id
230
234
  if "question" in self.explain_id:
231
235
  self.event_type = "question"
236
+ elif "grounding" in self.explain_id:
237
+ self.event_type = "grounding"
232
238
  elif "exploration" in self.explain_id:
233
239
  self.event_type = "exploration"
234
240
  elif "focus" in self.explain_id:
235
241
  self.event_type = "focus"
236
242
  elif "synthesis" in self.explain_id:
237
243
  self.event_type = "synthesis"
244
+ elif "iteration" in self.explain_id:
245
+ self.event_type = "iteration"
246
+ elif "observation" in self.explain_id:
247
+ self.event_type = "observation"
248
+ elif "conclusion" in self.explain_id:
249
+ self.event_type = "conclusion"
250
+ elif "decomposition" in self.explain_id:
251
+ self.event_type = "decomposition"
252
+ elif "finding" in self.explain_id:
253
+ self.event_type = "finding"
254
+ elif "plan" in self.explain_id:
255
+ self.event_type = "plan"
256
+ elif "step-result" in self.explain_id:
257
+ self.event_type = "step-result"
258
+ elif "session" in self.explain_id:
259
+ self.event_type = "session"
@@ -94,7 +94,6 @@ class AsyncProcessor:
94
94
  metrics = config_consumer_metrics,
95
95
 
96
96
  start_of_messages = False,
97
- consumer_type = 'exclusive',
98
97
  )
99
98
 
100
99
  self.running = True
@@ -172,7 +171,8 @@ class AsyncProcessor:
172
171
 
173
172
  except Exception as e:
174
173
  logger.warning(
175
- f"Config fetch failed: {e}, retrying in 2s..."
174
+ f"Config fetch failed: {e}, retrying in 2s...",
175
+ exc_info=True
176
176
  )
177
177
  await asyncio.sleep(2)
178
178
 
@@ -12,6 +12,7 @@
12
12
  import asyncio
13
13
  import time
14
14
  import logging
15
+ from concurrent.futures import ThreadPoolExecutor
15
16
 
16
17
  from .. exceptions import TooManyRequests
17
18
 
@@ -110,29 +111,37 @@ class Consumer:
110
111
  logger.info(f"Starting {self.concurrency} receiver threads")
111
112
 
112
113
  # Create one backend consumer per concurrent task.
113
- # Each gets its own connection required for backends
114
- # like RabbitMQ where connections are not thread-safe.
114
+ # Each gets its own connection and dedicated thread
115
+ # required for backends like RabbitMQ where connections
116
+ # are not thread-safe (pika BlockingConnection must be
117
+ # used from a single thread).
115
118
  consumers = []
119
+ executors = []
116
120
  for i in range(self.concurrency):
117
121
  try:
118
122
  logger.info(f"Subscribing to topic: {self.topic} (worker {i})")
119
- c = await asyncio.to_thread(
120
- self.backend.create_consumer,
121
- topic = self.topic,
122
- subscription = self.subscriber,
123
- schema = self.schema,
124
- initial_position = initial_pos,
125
- consumer_type = self.consumer_type,
123
+ executor = ThreadPoolExecutor(max_workers=1)
124
+ loop = asyncio.get_event_loop()
125
+ c = await loop.run_in_executor(
126
+ executor,
127
+ lambda: self.backend.create_consumer(
128
+ topic = self.topic,
129
+ subscription = self.subscriber,
130
+ schema = self.schema,
131
+ initial_position = initial_pos,
132
+ consumer_type = self.consumer_type,
133
+ ),
126
134
  )
127
135
  consumers.append(c)
136
+ executors.append(executor)
128
137
  logger.info(f"Successfully subscribed to topic: {self.topic} (worker {i})")
129
138
  except Exception as e:
130
139
  logger.error(f"Consumer subscription exception (worker {i}): {e}", exc_info=True)
131
140
  raise
132
141
 
133
142
  async with asyncio.TaskGroup() as tg:
134
- for c in consumers:
135
- tg.create_task(self.consume_from_queue(c))
143
+ for c, ex in zip(consumers, executors):
144
+ tg.create_task(self.consume_from_queue(c, ex))
136
145
 
137
146
  if self.metrics:
138
147
  self.metrics.state("stopped")
@@ -146,7 +155,10 @@ class Consumer:
146
155
  c.close()
147
156
  except Exception:
148
157
  pass
158
+ for ex in executors:
159
+ ex.shutdown(wait=False)
149
160
  consumers = []
161
+ executors = []
150
162
  await asyncio.sleep(self.reconnect_time)
151
163
  continue
152
164
 
@@ -157,15 +169,18 @@ class Consumer:
157
169
  c.close()
158
170
  except Exception:
159
171
  pass
172
+ for ex in executors:
173
+ ex.shutdown(wait=False)
160
174
 
161
- async def consume_from_queue(self, consumer):
175
+ async def consume_from_queue(self, consumer, executor=None):
162
176
 
177
+ loop = asyncio.get_event_loop()
163
178
  while self.running:
164
179
 
165
180
  try:
166
- msg = await asyncio.to_thread(
167
- consumer.receive,
168
- timeout_millis=2000
181
+ msg = await loop.run_in_executor(
182
+ executor,
183
+ lambda: consumer.receive(timeout_millis=100),
169
184
  )
170
185
  except Exception as e:
171
186
  # Handle timeout from any backend
@@ -173,10 +188,11 @@ class Consumer:
173
188
  continue
174
189
  raise e
175
190
 
176
- await self.handle_one_from_queue(msg, consumer)
191
+ await self.handle_one_from_queue(msg, consumer, executor)
177
192
 
178
- async def handle_one_from_queue(self, msg, consumer):
193
+ async def handle_one_from_queue(self, msg, consumer, executor=None):
179
194
 
195
+ loop = asyncio.get_event_loop()
180
196
  expiry = time.time() + self.rate_limit_timeout
181
197
 
182
198
  # This loop is for retry on rate-limit / resource limits
@@ -187,8 +203,11 @@ class Consumer:
187
203
  logger.warning("Gave up waiting for rate-limit retry")
188
204
 
189
205
  # Message failed to be processed, this causes it to
190
- # be retried
191
- consumer.negative_acknowledge(msg)
206
+ # be retried. Ack on the consumer's dedicated thread
207
+ # (pika is not thread-safe).
208
+ await loop.run_in_executor(
209
+ executor, lambda: consumer.negative_acknowledge(msg)
210
+ )
192
211
 
193
212
  if self.metrics:
194
213
  self.metrics.process("error")
@@ -210,8 +229,11 @@ class Consumer:
210
229
 
211
230
  logger.debug("Message processed successfully")
212
231
 
213
- # Acknowledge successful processing of the message
214
- consumer.acknowledge(msg)
232
+ # Acknowledge on the consumer's dedicated thread
233
+ # (pika is not thread-safe)
234
+ await loop.run_in_executor(
235
+ executor, lambda: consumer.acknowledge(msg)
236
+ )
215
237
 
216
238
  if self.metrics:
217
239
  self.metrics.process("success")
@@ -237,8 +259,10 @@ class Consumer:
237
259
  logger.error(f"Message processing exception: {e}", exc_info=True)
238
260
 
239
261
  # Message failed to be processed, this causes it to
240
- # be retried
241
- consumer.negative_acknowledge(msg)
262
+ # be retried. Ack on the consumer's dedicated thread.
263
+ await loop.run_in_executor(
264
+ executor, lambda: consumer.negative_acknowledge(msg)
265
+ )
242
266
 
243
267
  if self.metrics:
244
268
  self.metrics.process("error")
@@ -288,6 +288,7 @@ class RabbitMQBackend:
288
288
  port=port,
289
289
  virtual_host=vhost,
290
290
  credentials=pika.PlainCredentials(username, password),
291
+ heartbeat=0,
291
292
  )
292
293
  logger.info(f"RabbitMQ backend: {host}:{port} vhost={vhost}")
293
294
 
@@ -7,6 +7,7 @@ import asyncio
7
7
  import time
8
8
  import logging
9
9
  import uuid
10
+ from concurrent.futures import ThreadPoolExecutor
10
11
 
11
12
  # Module logger
12
13
  logger = logging.getLogger(__name__)
@@ -38,6 +39,7 @@ class Subscriber:
38
39
  self.pending_acks = {} # Track messages awaiting delivery
39
40
 
40
41
  self.consumer = None
42
+ self.executor = None
41
43
 
42
44
  def __del__(self):
43
45
 
@@ -45,15 +47,6 @@ class Subscriber:
45
47
 
46
48
  async def start(self):
47
49
 
48
- # Create consumer via backend
49
- self.consumer = await asyncio.to_thread(
50
- self.backend.create_consumer,
51
- topic=self.topic,
52
- subscription=self.subscription,
53
- schema=self.schema,
54
- consumer_type='exclusive',
55
- )
56
-
57
50
  self.task = asyncio.create_task(self.run())
58
51
 
59
52
  async def stop(self):
@@ -80,6 +73,21 @@ class Subscriber:
80
73
 
81
74
  try:
82
75
 
76
+ # Create consumer and dedicated thread if needed
77
+ # (first run or after failure)
78
+ if self.consumer is None:
79
+ self.executor = ThreadPoolExecutor(max_workers=1)
80
+ loop = asyncio.get_event_loop()
81
+ self.consumer = await loop.run_in_executor(
82
+ self.executor,
83
+ lambda: self.backend.create_consumer(
84
+ topic=self.topic,
85
+ subscription=self.subscription,
86
+ schema=self.schema,
87
+ consumer_type='exclusive',
88
+ ),
89
+ )
90
+
83
91
  if self.metrics:
84
92
  self.metrics.state("running")
85
93
 
@@ -128,9 +136,12 @@ class Subscriber:
128
136
  # Process messages only if not draining
129
137
  if not self.draining:
130
138
  try:
131
- msg = await asyncio.to_thread(
132
- self.consumer.receive,
133
- timeout_millis=250
139
+ loop = asyncio.get_event_loop()
140
+ msg = await loop.run_in_executor(
141
+ self.executor,
142
+ lambda: self.consumer.receive(
143
+ timeout_millis=250
144
+ ),
134
145
  )
135
146
  except Exception as e:
136
147
  # Handle timeout from any backend
@@ -172,15 +183,18 @@ class Subscriber:
172
183
  except Exception:
173
184
  pass # Already closed or error
174
185
  self.consumer = None
175
-
176
-
186
+
187
+ if self.executor:
188
+ self.executor.shutdown(wait=False)
189
+ self.executor = None
190
+
177
191
  if self.metrics:
178
192
  self.metrics.state("stopped")
179
193
 
180
194
  if not self.running and not self.draining:
181
195
  return
182
-
183
- # If handler drops out, sleep a retry
196
+
197
+ # Sleep before retry
184
198
  await asyncio.sleep(1)
185
199
 
186
200
  async def subscribe(self, id):
@@ -0,0 +1 @@
1
+ __version__ = "2.2.22"
@@ -1,6 +1,7 @@
1
1
  from typing import Dict, Any, Tuple
2
2
  from ...schema import AgentRequest, AgentResponse
3
3
  from .base import MessageTranslator
4
+ from .primitives import TripleTranslator
4
5
 
5
6
 
6
7
  class AgentRequestTranslator(MessageTranslator):
@@ -49,10 +50,13 @@ class AgentRequestTranslator(MessageTranslator):
49
50
 
50
51
  class AgentResponseTranslator(MessageTranslator):
51
52
  """Translator for AgentResponse schema objects"""
52
-
53
+
54
+ def __init__(self):
55
+ self.triple_translator = TripleTranslator()
56
+
53
57
  def decode(self, data: Dict[str, Any]) -> AgentResponse:
54
58
  raise NotImplementedError("Response translation to Pulsar not typically needed")
55
-
59
+
56
60
  def encode(self, obj: AgentResponse) -> Dict[str, Any]:
57
61
  result = {}
58
62
 
@@ -75,6 +79,13 @@ class AgentResponseTranslator(MessageTranslator):
75
79
  if explain_graph is not None:
76
80
  result["explain_graph"] = explain_graph
77
81
 
82
+ # Include explain_triples for explain messages
83
+ explain_triples = getattr(obj, "explain_triples", [])
84
+ if explain_triples:
85
+ result["explain_triples"] = [
86
+ self.triple_translator.encode(t) for t in explain_triples
87
+ ]
88
+
78
89
  # Always include error if present
79
90
  if hasattr(obj, 'error') and obj.error and obj.error.message:
80
91
  result["error"] = {"message": obj.error.message, "code": obj.error.code}
@@ -79,7 +79,6 @@ class CollectionManagementResponseTranslator(MessageTranslator):
79
79
  def encode(self, obj: CollectionManagementResponse) -> Dict[str, Any]:
80
80
  result = {}
81
81
 
82
- print("COLLECTIONMGMT", obj, flush=True)
83
82
 
84
83
  if obj.error is not None:
85
84
  result["error"] = {
@@ -99,6 +98,4 @@ class CollectionManagementResponseTranslator(MessageTranslator):
99
98
  "tags": list(coll.tags) if coll.tags else []
100
99
  })
101
100
 
102
- print("RESULT IS", result, flush=True)
103
-
104
101
  return result
@@ -1,6 +1,7 @@
1
1
  from typing import Dict, Any, Tuple
2
2
  from ...schema import DocumentRagQuery, DocumentRagResponse, GraphRagQuery, GraphRagResponse
3
3
  from .base import MessageTranslator
4
+ from .primitives import TripleTranslator
4
5
 
5
6
 
6
7
  class DocumentRagRequestTranslator(MessageTranslator):
@@ -28,6 +29,9 @@ class DocumentRagRequestTranslator(MessageTranslator):
28
29
  class DocumentRagResponseTranslator(MessageTranslator):
29
30
  """Translator for DocumentRagResponse schema objects"""
30
31
 
32
+ def __init__(self):
33
+ self.triple_translator = TripleTranslator()
34
+
31
35
  def decode(self, data: Dict[str, Any]) -> DocumentRagResponse:
32
36
  raise NotImplementedError("Response translation to Pulsar not typically needed")
33
37
 
@@ -53,6 +57,13 @@ class DocumentRagResponseTranslator(MessageTranslator):
53
57
  if explain_graph is not None:
54
58
  result["explain_graph"] = explain_graph
55
59
 
60
+ # Include explain_triples for explain messages
61
+ explain_triples = getattr(obj, "explain_triples", [])
62
+ if explain_triples:
63
+ result["explain_triples"] = [
64
+ self.triple_translator.encode(t) for t in explain_triples
65
+ ]
66
+
56
67
  # Include end_of_stream flag (LLM stream complete)
57
68
  result["end_of_stream"] = getattr(obj, "end_of_stream", False)
58
69
 
@@ -107,6 +118,9 @@ class GraphRagRequestTranslator(MessageTranslator):
107
118
  class GraphRagResponseTranslator(MessageTranslator):
108
119
  """Translator for GraphRagResponse schema objects"""
109
120
 
121
+ def __init__(self):
122
+ self.triple_translator = TripleTranslator()
123
+
110
124
  def decode(self, data: Dict[str, Any]) -> GraphRagResponse:
111
125
  raise NotImplementedError("Response translation to Pulsar not typically needed")
112
126
 
@@ -132,6 +146,13 @@ class GraphRagResponseTranslator(MessageTranslator):
132
146
  if explain_graph is not None:
133
147
  result["explain_graph"] = explain_graph
134
148
 
149
+ # Include explain_triples for explain messages
150
+ explain_triples = getattr(obj, "explain_triples", [])
151
+ if explain_triples:
152
+ result["explain_triples"] = [
153
+ self.triple_translator.encode(t) for t in explain_triples
154
+ ]
155
+
135
156
  # Include end_of_stream flag (LLM stream complete)
136
157
  result["end_of_stream"] = getattr(obj, "end_of_stream", False)
137
158
 
@@ -2,7 +2,7 @@
2
2
  from dataclasses import dataclass, field
3
3
  from typing import Optional
4
4
 
5
- from ..core.primitives import Error
5
+ from ..core.primitives import Error, Triple
6
6
 
7
7
  ############################################################################
8
8
 
@@ -57,8 +57,9 @@ class AgentResponse:
57
57
  end_of_dialog: bool = False # Entire agent dialog is complete
58
58
 
59
59
  # Explainability fields
60
- explain_id: str | None = None # Provenance URI (announced as created)
61
- explain_graph: str | None = None # Named graph where explain was stored
60
+ explain_id: str | None = None # Root URI for this explain step
61
+ explain_graph: str | None = None # Named graph (e.g., urn:graph:retrieval)
62
+ explain_triples: list[Triple] = field(default_factory=list) # Provenance triples for this step
62
63
 
63
64
  # Orchestration fields
64
65
  message_id: str = "" # Unique ID for this response message
@@ -1,5 +1,5 @@
1
- from dataclasses import dataclass
2
- from ..core.primitives import Error, Term
1
+ from dataclasses import dataclass, field
2
+ from ..core.primitives import Error, Term, Triple
3
3
 
4
4
  ############################################################################
5
5
 
@@ -24,8 +24,9 @@ class GraphRagResponse:
24
24
  error: Error | None = None
25
25
  response: str = ""
26
26
  end_of_stream: bool = False # LLM response stream complete
27
- explain_id: str | None = None # Single explain URI (announced as created)
28
- explain_graph: str | None = None # Named graph where explain was stored (e.g., urn:graph:retrieval)
27
+ explain_id: str | None = None # Root URI for this explain step
28
+ explain_graph: str | None = None # Named graph (e.g., urn:graph:retrieval)
29
+ explain_triples: list[Triple] = field(default_factory=list) # Provenance triples for this step
29
30
  message_type: str = "" # "chunk" or "explain"
30
31
  end_of_session: bool = False # Entire session complete
31
32
 
@@ -46,7 +47,8 @@ class DocumentRagResponse:
46
47
  error: Error | None = None
47
48
  response: str | None = ""
48
49
  end_of_stream: bool = False # LLM response stream complete
49
- explain_id: str | None = None # Single explain URI (announced as created)
50
- explain_graph: str | None = None # Named graph where explain was stored (e.g., urn:graph:retrieval)
50
+ explain_id: str | None = None # Root URI for this explain step
51
+ explain_graph: str | None = None # Named graph (e.g., urn:graph:retrieval)
52
+ explain_triples: list[Triple] = field(default_factory=list) # Provenance triples for this step
51
53
  message_type: str = "" # "chunk" or "explain"
52
54
  end_of_session: bool = False # Entire session complete
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trustgraph-base
3
- Version: 2.2.20
3
+ Version: 2.2.22
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
@@ -1 +0,0 @@
1
- __version__ = "2.2.20"