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