trustgraph-cli 1.3.7__tar.gz → 1.8.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.

Potentially problematic release.


This version of trustgraph-cli might be problematic. Click here for more details.

Files changed (85) hide show
  1. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/PKG-INFO +2 -2
  2. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/pyproject.toml +12 -5
  3. trustgraph_cli-1.8.14/trustgraph/cli/delete_collection.py +72 -0
  4. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/delete_config_item.py +10 -2
  5. trustgraph_cli-1.3.7/trustgraph/cli/delete_flow_class.py → trustgraph_cli-1.8.14/trustgraph/cli/delete_flow_blueprint.py +9 -9
  6. trustgraph_cli-1.8.14/trustgraph/cli/dump_queues.py +363 -0
  7. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/get_config_item.py +10 -2
  8. trustgraph_cli-1.3.7/trustgraph/cli/get_flow_class.py → trustgraph_cli-1.8.14/trustgraph/cli/get_flow_blueprint.py +9 -9
  9. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/get_kg_core.py +12 -1
  10. trustgraph_cli-1.8.14/trustgraph/cli/invoke_agent.py +296 -0
  11. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/invoke_document_rag.py +54 -12
  12. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/invoke_graph_rag.py +63 -14
  13. trustgraph_cli-1.8.14/trustgraph/cli/invoke_llm.py +103 -0
  14. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/invoke_prompt.py +43 -8
  15. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/invoke_structured_query.py +16 -2
  16. trustgraph_cli-1.8.14/trustgraph/cli/list_collections.py +84 -0
  17. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/list_config_items.py +10 -2
  18. trustgraph_cli-1.8.14/trustgraph/cli/load_knowledge.py +213 -0
  19. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/load_sample_documents.py +10 -2
  20. trustgraph_cli-1.8.14/trustgraph/cli/load_structured_data.py +1070 -0
  21. trustgraph_cli-1.8.14/trustgraph/cli/load_turtle.py +166 -0
  22. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/put_config_item.py +10 -2
  23. trustgraph_cli-1.3.7/trustgraph/cli/put_flow_class.py → trustgraph_cli-1.8.14/trustgraph/cli/put_flow_blueprint.py +19 -11
  24. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/put_kg_core.py +12 -1
  25. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/remove_library_document.py +10 -3
  26. trustgraph_cli-1.8.14/trustgraph/cli/set_collection.py +110 -0
  27. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/set_mcp_tool.py +35 -8
  28. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/set_prompt.py +14 -7
  29. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/set_token_costs.py +9 -2
  30. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/set_tool.py +34 -16
  31. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_config.py +10 -2
  32. trustgraph_cli-1.8.14/trustgraph/cli/show_flow_blueprints.py +130 -0
  33. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_flow_state.py +13 -6
  34. trustgraph_cli-1.8.14/trustgraph/cli/show_flows.py +223 -0
  35. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_graph.py +10 -2
  36. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_kg_cores.py +12 -3
  37. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_library_documents.py +12 -3
  38. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_library_processing.py +10 -3
  39. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_mcp_tools.py +16 -2
  40. trustgraph_cli-1.8.14/trustgraph/cli/show_parameter_types.py +217 -0
  41. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_prompts.py +10 -2
  42. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_token_costs.py +12 -4
  43. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_tools.py +37 -4
  44. trustgraph_cli-1.8.14/trustgraph/cli/start_flow.py +130 -0
  45. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/start_library_processing.py +11 -3
  46. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/stop_flow.py +10 -2
  47. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/stop_library_processing.py +10 -2
  48. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/unload_kg_core.py +10 -2
  49. trustgraph_cli-1.8.14/trustgraph/cli/verify_system_status.py +492 -0
  50. trustgraph_cli-1.8.14/trustgraph/cli_version.py +1 -0
  51. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph_cli.egg-info/PKG-INFO +2 -2
  52. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph_cli.egg-info/SOURCES.txt +11 -4
  53. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph_cli.egg-info/entry_points.txt +11 -4
  54. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph_cli.egg-info/requires.txt +1 -1
  55. trustgraph_cli-1.3.7/trustgraph/cli/invoke_agent.py +0 -171
  56. trustgraph_cli-1.3.7/trustgraph/cli/invoke_llm.py +0 -68
  57. trustgraph_cli-1.3.7/trustgraph/cli/load_knowledge.py +0 -202
  58. trustgraph_cli-1.3.7/trustgraph/cli/load_turtle.py +0 -159
  59. trustgraph_cli-1.3.7/trustgraph/cli/show_flow_classes.py +0 -67
  60. trustgraph_cli-1.3.7/trustgraph/cli/show_flows.py +0 -112
  61. trustgraph_cli-1.3.7/trustgraph/cli/start_flow.py +0 -70
  62. trustgraph_cli-1.3.7/trustgraph/cli_version.py +0 -1
  63. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/README.md +0 -0
  64. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/setup.cfg +0 -0
  65. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/__init__.py +0 -0
  66. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/add_library_document.py +0 -0
  67. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/delete_kg_core.py +0 -0
  68. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/delete_mcp_tool.py +0 -0
  69. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/delete_tool.py +0 -0
  70. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/dump_msgpack.py +0 -0
  71. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/graph_to_turtle.py +0 -0
  72. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/init_pulsar_manager.py +0 -0
  73. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/init_trustgraph.py +0 -0
  74. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/invoke_mcp_tool.py +0 -0
  75. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/invoke_nlp_query.py +0 -0
  76. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/invoke_objects_query.py +0 -0
  77. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/load_doc_embeds.py +0 -0
  78. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/load_kg_core.py +0 -0
  79. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/load_pdf.py +0 -0
  80. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/load_text.py +0 -0
  81. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/save_doc_embeds.py +0 -0
  82. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_processor_state.py +0 -0
  83. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph/cli/show_token_rate.py +0 -0
  84. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph_cli.egg-info/dependency_links.txt +0 -0
  85. {trustgraph_cli-1.3.7 → trustgraph_cli-1.8.14}/trustgraph_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trustgraph-cli
3
- Version: 1.3.7
3
+ Version: 1.8.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
@@ -8,7 +8,7 @@ Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Operating System :: OS Independent
9
9
  Requires-Python: >=3.8
10
10
  Description-Content-Type: text/markdown
11
- Requires-Dist: trustgraph-base<1.4,>=1.3
11
+ Requires-Dist: trustgraph-base<1.9,>=1.8
12
12
  Requires-Dist: requests
13
13
  Requires-Dist: pulsar-client
14
14
  Requires-Dist: aiohttp
@@ -10,7 +10,7 @@ description = "TrustGraph provides a means to run a pipeline of flexible AI proc
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.8"
12
12
  dependencies = [
13
- "trustgraph-base>=1.3,<1.4",
13
+ "trustgraph-base>=1.8,<1.9",
14
14
  "requests",
15
15
  "pulsar-client",
16
16
  "aiohttp",
@@ -29,12 +29,13 @@ Homepage = "https://github.com/trustgraph-ai/trustgraph"
29
29
 
30
30
  [project.scripts]
31
31
  tg-add-library-document = "trustgraph.cli.add_library_document:main"
32
- tg-delete-flow-class = "trustgraph.cli.delete_flow_class:main"
32
+ tg-delete-flow-blueprint = "trustgraph.cli.delete_flow_blueprint:main"
33
33
  tg-delete-mcp-tool = "trustgraph.cli.delete_mcp_tool:main"
34
34
  tg-delete-kg-core = "trustgraph.cli.delete_kg_core:main"
35
35
  tg-delete-tool = "trustgraph.cli.delete_tool:main"
36
36
  tg-dump-msgpack = "trustgraph.cli.dump_msgpack:main"
37
- tg-get-flow-class = "trustgraph.cli.get_flow_class:main"
37
+ tg-dump-queues = "trustgraph.cli.dump_queues:main"
38
+ tg-get-flow-blueprint = "trustgraph.cli.get_flow_blueprint:main"
38
39
  tg-get-kg-core = "trustgraph.cli.get_kg_core:main"
39
40
  tg-graph-to-turtle = "trustgraph.cli.graph_to_turtle:main"
40
41
  tg-init-trustgraph = "trustgraph.cli.init_trustgraph:main"
@@ -54,7 +55,8 @@ tg-load-sample-documents = "trustgraph.cli.load_sample_documents:main"
54
55
  tg-load-text = "trustgraph.cli.load_text:main"
55
56
  tg-load-turtle = "trustgraph.cli.load_turtle:main"
56
57
  tg-load-knowledge = "trustgraph.cli.load_knowledge:main"
57
- tg-put-flow-class = "trustgraph.cli.put_flow_class:main"
58
+ tg-load-structured-data = "trustgraph.cli.load_structured_data:main"
59
+ tg-put-flow-blueprint = "trustgraph.cli.put_flow_blueprint:main"
58
60
  tg-put-kg-core = "trustgraph.cli.put_kg_core:main"
59
61
  tg-remove-library-document = "trustgraph.cli.remove_library_document:main"
60
62
  tg-save-doc-embeds = "trustgraph.cli.save_doc_embeds:main"
@@ -63,7 +65,7 @@ tg-set-prompt = "trustgraph.cli.set_prompt:main"
63
65
  tg-set-token-costs = "trustgraph.cli.set_token_costs:main"
64
66
  tg-set-tool = "trustgraph.cli.set_tool:main"
65
67
  tg-show-config = "trustgraph.cli.show_config:main"
66
- tg-show-flow-classes = "trustgraph.cli.show_flow_classes:main"
68
+ tg-show-flow-blueprints = "trustgraph.cli.show_flow_blueprints:main"
67
69
  tg-show-flow-state = "trustgraph.cli.show_flow_state:main"
68
70
  tg-show-flows = "trustgraph.cli.show_flows:main"
69
71
  tg-show-graph = "trustgraph.cli.show_graph:main"
@@ -71,6 +73,7 @@ tg-show-kg-cores = "trustgraph.cli.show_kg_cores:main"
71
73
  tg-show-library-documents = "trustgraph.cli.show_library_documents:main"
72
74
  tg-show-library-processing = "trustgraph.cli.show_library_processing:main"
73
75
  tg-show-mcp-tools = "trustgraph.cli.show_mcp_tools:main"
76
+ tg-show-parameter-types = "trustgraph.cli.show_parameter_types:main"
74
77
  tg-show-processor-state = "trustgraph.cli.show_processor_state:main"
75
78
  tg-show-prompts = "trustgraph.cli.show_prompts:main"
76
79
  tg-show-token-costs = "trustgraph.cli.show_token_costs:main"
@@ -81,10 +84,14 @@ tg-unload-kg-core = "trustgraph.cli.unload_kg_core:main"
81
84
  tg-start-library-processing = "trustgraph.cli.start_library_processing:main"
82
85
  tg-stop-flow = "trustgraph.cli.stop_flow:main"
83
86
  tg-stop-library-processing = "trustgraph.cli.stop_library_processing:main"
87
+ tg-verify-system-status = "trustgraph.cli.verify_system_status:main"
84
88
  tg-list-config-items = "trustgraph.cli.list_config_items:main"
85
89
  tg-get-config-item = "trustgraph.cli.get_config_item:main"
86
90
  tg-put-config-item = "trustgraph.cli.put_config_item:main"
87
91
  tg-delete-config-item = "trustgraph.cli.delete_config_item:main"
92
+ tg-list-collections = "trustgraph.cli.list_collections:main"
93
+ tg-set-collection = "trustgraph.cli.set_collection:main"
94
+ tg-delete-collection = "trustgraph.cli.delete_collection:main"
88
95
 
89
96
  [tool.setuptools.packages.find]
90
97
  include = ["trustgraph*"]
@@ -0,0 +1,72 @@
1
+ """
2
+ Delete a collection and all its data
3
+ """
4
+
5
+ import argparse
6
+ import os
7
+ from trustgraph.api import Api
8
+
9
+ default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
10
+ default_user = "trustgraph"
11
+
12
+ def delete_collection(url, user, collection, confirm):
13
+
14
+ if not confirm:
15
+ response = input(f"Are you sure you want to delete collection '{collection}' and all its data? (y/N): ")
16
+ if response.lower() not in ['y', 'yes']:
17
+ print("Operation cancelled.")
18
+ return
19
+
20
+ api = Api(url).collection()
21
+
22
+ api.delete_collection(user=user, collection=collection)
23
+
24
+ print(f"Collection '{collection}' deleted successfully.")
25
+
26
+ def main():
27
+
28
+ parser = argparse.ArgumentParser(
29
+ prog='tg-delete-collection',
30
+ description=__doc__,
31
+ )
32
+
33
+ parser.add_argument(
34
+ 'collection',
35
+ help='Collection ID to delete'
36
+ )
37
+
38
+ parser.add_argument(
39
+ '-u', '--api-url',
40
+ default=default_url,
41
+ help=f'API URL (default: {default_url})',
42
+ )
43
+
44
+ parser.add_argument(
45
+ '-U', '--user',
46
+ default=default_user,
47
+ help=f'User ID (default: {default_user})'
48
+ )
49
+
50
+ parser.add_argument(
51
+ '-y', '--yes',
52
+ action='store_true',
53
+ help='Skip confirmation prompt'
54
+ )
55
+
56
+ args = parser.parse_args()
57
+
58
+ try:
59
+
60
+ delete_collection(
61
+ url = args.api_url,
62
+ user = args.user,
63
+ collection = args.collection,
64
+ confirm = args.yes
65
+ )
66
+
67
+ except Exception as e:
68
+
69
+ print("Exception:", e, flush=True)
70
+
71
+ if __name__ == "__main__":
72
+ main()
@@ -8,10 +8,11 @@ from trustgraph.api import Api
8
8
  from trustgraph.api.types import ConfigKey
9
9
 
10
10
  default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
11
+ default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
11
12
 
12
- def delete_config_item(url, config_type, key):
13
+ def delete_config_item(url, config_type, key, token=None):
13
14
 
14
- api = Api(url).config()
15
+ api = Api(url, token=token).config()
15
16
 
16
17
  config_key = ConfigKey(type=config_type, key=key)
17
18
  api.delete([config_key])
@@ -43,6 +44,12 @@ def main():
43
44
  help=f'API URL (default: {default_url})',
44
45
  )
45
46
 
47
+ parser.add_argument(
48
+ '-t', '--token',
49
+ default=default_token,
50
+ help='Authentication token (default: $TRUSTGRAPH_TOKEN)',
51
+ )
52
+
46
53
  args = parser.parse_args()
47
54
 
48
55
  try:
@@ -51,6 +58,7 @@ def main():
51
58
  url=args.api_url,
52
59
  config_type=args.type,
53
60
  key=args.key,
61
+ token=args.token,
54
62
  )
55
63
 
56
64
  except Exception as e:
@@ -1,5 +1,5 @@
1
1
  """
2
- Deletes a flow class
2
+ Deletes a flow blueprint
3
3
  """
4
4
 
5
5
  import argparse
@@ -10,16 +10,16 @@ import json
10
10
 
11
11
  default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
12
12
 
13
- def delete_flow_class(url, class_name):
13
+ def delete_flow_blueprint(url, blueprint_name):
14
14
 
15
15
  api = Api(url).flow()
16
16
 
17
- class_names = api.delete_class(class_name)
17
+ blueprint_names = api.delete_blueprint(blueprint_name)
18
18
 
19
19
  def main():
20
20
 
21
21
  parser = argparse.ArgumentParser(
22
- prog='tg-delete-flow-class',
22
+ prog='tg-delete-flow-blueprint',
23
23
  description=__doc__,
24
24
  )
25
25
 
@@ -30,17 +30,17 @@ def main():
30
30
  )
31
31
 
32
32
  parser.add_argument(
33
- '-n', '--class-name',
34
- help=f'Flow class name',
33
+ '-n', '--blueprint-name',
34
+ help=f'Flow blueprint name',
35
35
  )
36
36
 
37
37
  args = parser.parse_args()
38
38
 
39
39
  try:
40
40
 
41
- delete_flow_class(
41
+ delete_flow_blueprint(
42
42
  url=args.api_url,
43
- class_name=args.class_name,
43
+ blueprint_name=args.blueprint_name,
44
44
  )
45
45
 
46
46
  except Exception as e:
@@ -48,4 +48,4 @@ def main():
48
48
  print("Exception:", e, flush=True)
49
49
 
50
50
  if __name__ == "__main__":
51
- main()
51
+ main()
@@ -0,0 +1,363 @@
1
+ """
2
+ Multi-queue Pulsar message dumper for debugging TrustGraph message flows.
3
+
4
+ This utility monitors multiple Pulsar queues simultaneously and logs all messages
5
+ to a file with timestamps and pretty-printed formatting. Useful for debugging
6
+ message flows, diagnosing stuck services, and understanding system behavior.
7
+
8
+ Uses TrustGraph's Subscriber abstraction for future-proof pub/sub compatibility.
9
+ """
10
+
11
+ import pulsar
12
+ from pulsar.schema import BytesSchema
13
+ import sys
14
+ import json
15
+ import asyncio
16
+ from datetime import datetime
17
+ import argparse
18
+
19
+ from trustgraph.base.subscriber import Subscriber
20
+ from trustgraph.base.pubsub import get_pubsub
21
+
22
+ def format_message(queue_name, msg):
23
+ """Format a message with timestamp and queue name."""
24
+ timestamp = datetime.now().isoformat()
25
+
26
+ # Try to parse as JSON and pretty-print
27
+ try:
28
+ # Handle both Message objects and raw bytes
29
+ if hasattr(msg, 'value'):
30
+ # Message object with .value() method
31
+ value = msg.value()
32
+ else:
33
+ # Raw bytes from schema-less subscription
34
+ value = msg
35
+
36
+ # If it's bytes, decode it
37
+ if isinstance(value, bytes):
38
+ value = value.decode('utf-8')
39
+
40
+ # If it's a string, try to parse as JSON
41
+ if isinstance(value, str):
42
+ try:
43
+ parsed = json.loads(value)
44
+ body = json.dumps(parsed, indent=2)
45
+ except (json.JSONDecodeError, TypeError):
46
+ body = value
47
+ else:
48
+ # Try to convert to dict for pretty printing
49
+ try:
50
+ # Pulsar schema objects have __dict__ or similar
51
+ if hasattr(value, '__dict__'):
52
+ parsed = {k: v for k, v in value.__dict__.items()
53
+ if not k.startswith('_')}
54
+ else:
55
+ parsed = str(value)
56
+ body = json.dumps(parsed, indent=2, default=str)
57
+ except (TypeError, AttributeError):
58
+ body = str(value)
59
+
60
+ except Exception as e:
61
+ body = f"<Error formatting message: {e}>\n{str(msg)}"
62
+
63
+ # Format the output
64
+ header = f"\n{'='*80}\n[{timestamp}] Queue: {queue_name}\n{'='*80}\n"
65
+ return header + body + "\n"
66
+
67
+
68
+ async def monitor_queue(subscriber, queue_name, central_queue, monitor_id, shutdown_event):
69
+ """
70
+ Monitor a single queue via Subscriber and forward messages to central queue.
71
+
72
+ Args:
73
+ subscriber: Subscriber instance for this queue
74
+ queue_name: Name of the queue (for logging)
75
+ central_queue: asyncio.Queue to forward messages to
76
+ monitor_id: Unique ID for this monitor's subscription
77
+ shutdown_event: asyncio.Event to signal shutdown
78
+ """
79
+ msg_queue = None
80
+ try:
81
+ # Subscribe to all messages from this Subscriber
82
+ msg_queue = await subscriber.subscribe_all(monitor_id)
83
+
84
+ while not shutdown_event.is_set():
85
+ try:
86
+ # Read from Subscriber's internal queue with timeout
87
+ msg = await asyncio.wait_for(msg_queue.get(), timeout=0.5)
88
+ timestamp = datetime.now()
89
+ formatted = format_message(queue_name, msg)
90
+
91
+ # Forward to central queue for writing
92
+ await central_queue.put((timestamp, queue_name, formatted))
93
+ except asyncio.TimeoutError:
94
+ # No message, check shutdown flag again
95
+ continue
96
+
97
+ except Exception as e:
98
+ if not shutdown_event.is_set():
99
+ error_msg = f"\n{'='*80}\n[{datetime.now().isoformat()}] ERROR in monitor for {queue_name}\n{'='*80}\n{e}\n"
100
+ await central_queue.put((datetime.now(), queue_name, error_msg))
101
+ finally:
102
+ # Clean unsubscribe
103
+ if msg_queue is not None:
104
+ try:
105
+ await subscriber.unsubscribe_all(monitor_id)
106
+ except Exception:
107
+ pass
108
+
109
+
110
+ async def log_writer(central_queue, file_handle, shutdown_event, console_output=True):
111
+ """
112
+ Write messages from central queue to file.
113
+
114
+ Args:
115
+ central_queue: asyncio.Queue containing (timestamp, queue_name, formatted_msg) tuples
116
+ file_handle: Open file handle to write to
117
+ shutdown_event: asyncio.Event to signal shutdown
118
+ console_output: Whether to print abbreviated messages to console
119
+ """
120
+ try:
121
+ while not shutdown_event.is_set():
122
+ try:
123
+ # Wait for messages with timeout to check shutdown flag
124
+ timestamp, queue_name, formatted_msg = await asyncio.wait_for(
125
+ central_queue.get(), timeout=0.5
126
+ )
127
+
128
+ # Write to file
129
+ file_handle.write(formatted_msg)
130
+ file_handle.flush()
131
+
132
+ # Print abbreviated message to console
133
+ if console_output:
134
+ time_str = timestamp.strftime('%H:%M:%S')
135
+ print(f"[{time_str}] {queue_name}: Message received")
136
+ except asyncio.TimeoutError:
137
+ # No message, check shutdown flag again
138
+ continue
139
+
140
+ finally:
141
+ # Flush remaining messages after shutdown
142
+ while not central_queue.empty():
143
+ try:
144
+ timestamp, queue_name, formatted_msg = central_queue.get_nowait()
145
+ file_handle.write(formatted_msg)
146
+ file_handle.flush()
147
+ except asyncio.QueueEmpty:
148
+ break
149
+
150
+
151
+ async def async_main(queues, output_file, pulsar_host, listener_name, subscriber_name, append_mode):
152
+ """
153
+ Main async function to monitor multiple queues concurrently.
154
+
155
+ Args:
156
+ queues: List of queue names to monitor
157
+ output_file: Path to output file
158
+ pulsar_host: Pulsar connection URL
159
+ listener_name: Pulsar listener name
160
+ subscriber_name: Base name for subscribers
161
+ append_mode: Whether to append to existing file
162
+ """
163
+ print(f"TrustGraph Queue Dumper")
164
+ print(f"Monitoring {len(queues)} queue(s):")
165
+ for q in queues:
166
+ print(f" - {q}")
167
+ print(f"Output file: {output_file}")
168
+ print(f"Mode: {'append' if append_mode else 'overwrite'}")
169
+ print(f"Press Ctrl+C to stop\n")
170
+
171
+ # Create backend connection
172
+ try:
173
+ backend = get_pubsub(pulsar_host=pulsar_host, pulsar_listener=listener_name, pubsub_backend='pulsar')
174
+ except Exception as e:
175
+ print(f"Error connecting to backend at {pulsar_host}: {e}", file=sys.stderr)
176
+ sys.exit(1)
177
+
178
+ # Create Subscribers and central queue
179
+ central_queue = asyncio.Queue()
180
+ subscribers = []
181
+
182
+ for queue_name in queues:
183
+ try:
184
+ sub = Subscriber(
185
+ backend=backend,
186
+ topic=queue_name,
187
+ subscription=subscriber_name,
188
+ consumer_name=f"{subscriber_name}-{queue_name}",
189
+ schema=None, # No schema - accept any message type
190
+ )
191
+ await sub.start()
192
+ subscribers.append((queue_name, sub))
193
+ print(f"✓ Subscribed to: {queue_name}")
194
+ except Exception as e:
195
+ print(f"✗ Error subscribing to {queue_name}: {e}", file=sys.stderr)
196
+
197
+ if not subscribers:
198
+ print("\nNo subscribers created. Exiting.", file=sys.stderr)
199
+ backend.close()
200
+ sys.exit(1)
201
+
202
+ print(f"\nListening for messages...\n")
203
+
204
+ # Open output file
205
+ mode = 'a' if append_mode else 'w'
206
+ try:
207
+ with open(output_file, mode) as f:
208
+ f.write(f"\n{'#'*80}\n")
209
+ f.write(f"# Session started: {datetime.now().isoformat()}\n")
210
+ f.write(f"# Monitoring queues: {', '.join(queues)}\n")
211
+ f.write(f"{'#'*80}\n")
212
+ f.flush()
213
+
214
+ # Create shutdown event for clean coordination
215
+ shutdown_event = asyncio.Event()
216
+
217
+ # Start monitoring tasks
218
+ tasks = []
219
+ try:
220
+ # Create one monitor task per subscriber
221
+ for queue_name, sub in subscribers:
222
+ task = asyncio.create_task(
223
+ monitor_queue(sub, queue_name, central_queue, "logger", shutdown_event)
224
+ )
225
+ tasks.append(task)
226
+
227
+ # Create single writer task
228
+ writer_task = asyncio.create_task(
229
+ log_writer(central_queue, f, shutdown_event)
230
+ )
231
+ tasks.append(writer_task)
232
+
233
+ # Wait for all tasks (they check shutdown_event)
234
+ await asyncio.gather(*tasks)
235
+
236
+ except KeyboardInterrupt:
237
+ print("\n\nStopping...")
238
+ finally:
239
+ # Signal shutdown to all tasks
240
+ shutdown_event.set()
241
+
242
+ # Wait for tasks to finish cleanly (with timeout)
243
+ try:
244
+ await asyncio.wait_for(asyncio.gather(*tasks, return_exceptions=True), timeout=2.0)
245
+ except asyncio.TimeoutError:
246
+ print("Warning: Shutdown timeout", file=sys.stderr)
247
+
248
+ # Write session end marker
249
+ f.write(f"\n{'#'*80}\n")
250
+ f.write(f"# Session ended: {datetime.now().isoformat()}\n")
251
+ f.write(f"{'#'*80}\n")
252
+
253
+ except IOError as e:
254
+ print(f"Error writing to {output_file}: {e}", file=sys.stderr)
255
+ sys.exit(1)
256
+ finally:
257
+ # Clean shutdown of Subscribers
258
+ for _, sub in subscribers:
259
+ await sub.stop()
260
+ backend.close()
261
+
262
+ print(f"\nMessages logged to: {output_file}")
263
+
264
+ def main():
265
+ parser = argparse.ArgumentParser(
266
+ prog='tg-dump-queues',
267
+ description='Monitor and dump messages from multiple Pulsar queues',
268
+ epilog="""
269
+ Examples:
270
+ # Monitor agent and prompt queues
271
+ tg-dump-queues non-persistent://tg/request/agent:default \\
272
+ non-persistent://tg/request/prompt:default
273
+
274
+ # Monitor with custom output file
275
+ tg-dump-queues non-persistent://tg/request/agent:default \\
276
+ --output debug.log
277
+
278
+ # Append to existing log file
279
+ tg-dump-queues non-persistent://tg/request/agent:default \\
280
+ --output queue.log --append
281
+
282
+ Common queue patterns:
283
+ - Agent requests: non-persistent://tg/request/agent:default
284
+ - Agent responses: non-persistent://tg/response/agent:default
285
+ - Prompt requests: non-persistent://tg/request/prompt:default
286
+ - Prompt responses: non-persistent://tg/response/prompt:default
287
+ - LLM requests: non-persistent://tg/request/text-completion:default
288
+ - LLM responses: non-persistent://tg/response/text-completion:default
289
+
290
+ IMPORTANT:
291
+ This tool subscribes to queues without a schema (schema-less mode). To avoid
292
+ schema conflicts, ensure that TrustGraph services and flows are already started
293
+ before running this tool. If this tool subscribes first, the real services may
294
+ encounter schema mismatch errors when they try to connect.
295
+
296
+ Best practice: Start services → Set up flows → Run tg-dump-queues
297
+ """,
298
+ formatter_class=argparse.RawDescriptionHelpFormatter
299
+ )
300
+
301
+ parser.add_argument(
302
+ 'queues',
303
+ nargs='+',
304
+ help='Pulsar queue names to monitor'
305
+ )
306
+
307
+ parser.add_argument(
308
+ '--output', '-o',
309
+ default='queue.log',
310
+ help='Output file (default: queue.log)'
311
+ )
312
+
313
+ parser.add_argument(
314
+ '--append', '-a',
315
+ action='store_true',
316
+ help='Append to output file instead of overwriting'
317
+ )
318
+
319
+ parser.add_argument(
320
+ '--pulsar-host',
321
+ default='pulsar://localhost:6650',
322
+ help='Pulsar host URL (default: pulsar://localhost:6650)'
323
+ )
324
+
325
+ parser.add_argument(
326
+ '--listener-name',
327
+ default='localhost',
328
+ help='Pulsar listener name (default: localhost)'
329
+ )
330
+
331
+ parser.add_argument(
332
+ '--subscriber',
333
+ default='debug',
334
+ help='Subscriber name for queue subscription (default: debug)'
335
+ )
336
+
337
+ args = parser.parse_args()
338
+
339
+ # Filter out any accidentally included flags
340
+ queues = [q for q in args.queues if not q.startswith('--')]
341
+
342
+ if not queues:
343
+ parser.error("No queues specified")
344
+
345
+ # Run async main
346
+ try:
347
+ asyncio.run(async_main(
348
+ queues=queues,
349
+ output_file=args.output,
350
+ pulsar_host=args.pulsar_host,
351
+ listener_name=args.listener_name,
352
+ subscriber_name=args.subscriber,
353
+ append_mode=args.append
354
+ ))
355
+ except KeyboardInterrupt:
356
+ # Already handled in async_main
357
+ pass
358
+ except Exception as e:
359
+ print(f"Fatal error: {e}", file=sys.stderr)
360
+ sys.exit(1)
361
+
362
+ if __name__ == '__main__':
363
+ main()
@@ -9,10 +9,11 @@ from trustgraph.api import Api
9
9
  from trustgraph.api.types import ConfigKey
10
10
 
11
11
  default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
12
+ default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
12
13
 
13
- def get_config_item(url, config_type, key, format_type):
14
+ def get_config_item(url, config_type, key, format_type, token=None):
14
15
 
15
- api = Api(url).config()
16
+ api = Api(url, token=token).config()
16
17
 
17
18
  config_key = ConfigKey(type=config_type, key=key)
18
19
  values = api.get([config_key])
@@ -59,6 +60,12 @@ def main():
59
60
  help=f'API URL (default: {default_url})',
60
61
  )
61
62
 
63
+ parser.add_argument(
64
+ '-t', '--token',
65
+ default=default_token,
66
+ help='Authentication token (default: $TRUSTGRAPH_TOKEN)',
67
+ )
68
+
62
69
  args = parser.parse_args()
63
70
 
64
71
  try:
@@ -68,6 +75,7 @@ def main():
68
75
  config_type=args.type,
69
76
  key=args.key,
70
77
  format_type=args.format,
78
+ token=args.token,
71
79
  )
72
80
 
73
81
  except Exception as e: