trustgraph-cli 2.8.0__tar.gz → 2.8.2__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.
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/PKG-INFO +1 -1
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/dump_queues.py +36 -47
- trustgraph_cli-2.8.2/trustgraph/cli/monitor_prompts.py +330 -0
- trustgraph_cli-2.8.2/trustgraph/cli_version.py +1 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph_cli.egg-info/PKG-INFO +1 -1
- trustgraph_cli-2.8.0/trustgraph/cli/monitor_prompts.py +0 -328
- trustgraph_cli-2.8.0/trustgraph/cli_version.py +0 -1
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/README.md +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/pyproject.toml +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/setup.cfg +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/__init__.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/_iam.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/add_library_document.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/bootstrap_iam.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/change_password.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/create_api_key.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/create_user.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/create_workspace.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/delete_collection.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/delete_config_item.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/delete_flow_blueprint.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/delete_kg_core.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/delete_mcp_tool.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/delete_tool.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/delete_user.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/describe_image.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/disable_user.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/dump_msgpack.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/enable_user.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/export_workspace.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/export_workspace_config.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/get_config_item.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/get_de_core.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/get_document_content.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/get_flow_blueprint.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/get_kg_core.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/graph_to_turtle.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/import_workspace.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/import_workspace_config.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/init_pulsar_manager.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_agent.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_document_embeddings.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_document_rag.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_embeddings.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_graph_embeddings.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_graph_rag.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_llm.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_mcp_tool.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_nlp_query.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_prompt.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_reranker.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_row_embeddings.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_rows_query.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_sparql_query.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/invoke_structured_query.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/list_api_keys.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/list_collections.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/list_config_items.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/list_explain_traces.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/list_my_workspaces.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/list_users.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/list_workspaces.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/load_doc_embeds.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/load_kg_core.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/load_knowledge.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/load_sample_documents.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/load_structured_data.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/load_turtle.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/login.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/nquads.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/put_config_item.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/put_de_core.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/put_flow_blueprint.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/put_kg_core.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/query_graph.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/remove_library_document.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/reset_password.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/revoke_api_key.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/__init__.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/belgian-beer.md +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/bronze-age-collapse.pdf +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/corporate-scandals.pdf +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/history-of-pets.md +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/metadata.json +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/mil-fortifications-america-19th-c.md +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/recipes.md +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/sample_documents/trade-routes-europe.md +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/save_doc_embeds.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/set_collection.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/set_mcp_tool.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/set_prompt.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/set_token_costs.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/set_tool.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_config.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_explain_trace.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_extraction_provenance.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_flow_blueprints.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_flow_state.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_flows.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_graph.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_kg_cores.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_library_documents.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_library_processing.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_mcp_tools.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_parameter_types.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_processor_state.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_prompts.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_token_costs.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_token_rate.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/show_tools.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/start_flow.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/start_library_processing.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/stop_flow.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/stop_library_processing.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/unload_kg_core.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/update_user.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/verify_system_status.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph/cli/whoami.py +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph_cli.egg-info/SOURCES.txt +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph_cli.egg-info/dependency_links.txt +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph_cli.egg-info/entry_points.txt +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/trustgraph_cli.egg-info/requires.txt +0 -0
- {trustgraph_cli-2.8.0 → trustgraph_cli-2.8.2}/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: 2.8.
|
|
3
|
+
Version: 2.8.2
|
|
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,11 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Multi-queue
|
|
2
|
+
Multi-queue message dumper for debugging TrustGraph message flows.
|
|
3
3
|
|
|
4
|
-
This utility monitors multiple
|
|
4
|
+
This utility monitors multiple queues simultaneously and logs all messages
|
|
5
5
|
to a file with timestamps and pretty-printed formatting. Useful for debugging
|
|
6
6
|
message flows, diagnosing stuck services, and understanding system behavior.
|
|
7
7
|
|
|
8
|
-
Uses TrustGraph's
|
|
8
|
+
Uses TrustGraph's async pub/sub backend for future-proof compatibility.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import sys
|
|
@@ -14,8 +14,7 @@ import asyncio
|
|
|
14
14
|
from datetime import datetime
|
|
15
15
|
import argparse
|
|
16
16
|
|
|
17
|
-
from trustgraph.base.
|
|
18
|
-
from trustgraph.base.pubsub import get_pubsub, add_pubsub_args
|
|
17
|
+
from trustgraph.base.pubsub import get_async_pubsub, add_pubsub_args
|
|
19
18
|
|
|
20
19
|
def decode_json_strings(obj):
|
|
21
20
|
"""Recursively decode JSON-encoded string values within a dict/list."""
|
|
@@ -54,7 +53,7 @@ def to_dict(value):
|
|
|
54
53
|
if isinstance(value, (list, tuple)):
|
|
55
54
|
return [to_dict(v) for v in value]
|
|
56
55
|
|
|
57
|
-
#
|
|
56
|
+
# Schema objects expose fields via __dict__
|
|
58
57
|
if hasattr(value, '__dict__'):
|
|
59
58
|
return {
|
|
60
59
|
k: to_dict(v) for k, v in value.__dict__.items()
|
|
@@ -87,31 +86,27 @@ def format_message(queue_name, msg):
|
|
|
87
86
|
return header + body + "\n"
|
|
88
87
|
|
|
89
88
|
|
|
90
|
-
async def monitor_queue(
|
|
89
|
+
async def monitor_queue(consumer, queue_name, central_queue, shutdown_event):
|
|
91
90
|
"""
|
|
92
|
-
Monitor a single queue via
|
|
91
|
+
Monitor a single queue via async consumer and forward messages to central queue.
|
|
93
92
|
|
|
94
93
|
Args:
|
|
95
|
-
|
|
94
|
+
consumer: Async consumer instance for this queue
|
|
96
95
|
queue_name: Name of the queue (for logging)
|
|
97
96
|
central_queue: asyncio.Queue to forward messages to
|
|
98
|
-
monitor_id: Unique ID for this monitor's subscription
|
|
99
97
|
shutdown_event: asyncio.Event to signal shutdown
|
|
100
98
|
"""
|
|
101
|
-
msg_queue = None
|
|
102
99
|
try:
|
|
103
|
-
# Subscribe to all messages from this Subscriber
|
|
104
|
-
msg_queue = await subscriber.subscribe_all(monitor_id)
|
|
105
|
-
|
|
106
100
|
while not shutdown_event.is_set():
|
|
107
101
|
try:
|
|
108
|
-
|
|
109
|
-
msg = await asyncio.wait_for(msg_queue.get(), timeout=0.5)
|
|
102
|
+
msg = await asyncio.wait_for(consumer.receive(), timeout=0.5)
|
|
110
103
|
timestamp = datetime.now()
|
|
111
104
|
formatted = format_message(queue_name, msg)
|
|
112
105
|
|
|
113
106
|
# Forward to central queue for writing
|
|
114
107
|
await central_queue.put((timestamp, queue_name, formatted))
|
|
108
|
+
|
|
109
|
+
await consumer.acknowledge(msg)
|
|
115
110
|
except asyncio.TimeoutError:
|
|
116
111
|
# No message, check shutdown flag again
|
|
117
112
|
continue
|
|
@@ -120,13 +115,6 @@ async def monitor_queue(subscriber, queue_name, central_queue, monitor_id, shutd
|
|
|
120
115
|
if not shutdown_event.is_set():
|
|
121
116
|
error_msg = f"\n{'='*80}\n[{datetime.now().isoformat()}] ERROR in monitor for {queue_name}\n{'='*80}\n{e}\n"
|
|
122
117
|
await central_queue.put((datetime.now(), queue_name, error_msg))
|
|
123
|
-
finally:
|
|
124
|
-
# Clean unsubscribe
|
|
125
|
-
if msg_queue is not None:
|
|
126
|
-
try:
|
|
127
|
-
await subscriber.unsubscribe_all(monitor_id)
|
|
128
|
-
except Exception:
|
|
129
|
-
pass
|
|
130
118
|
|
|
131
119
|
|
|
132
120
|
async def log_writer(central_queue, file_handle, shutdown_event, console_output=True):
|
|
@@ -190,33 +178,31 @@ async def async_main(queues, output_file, subscriber_name, append_mode, **pubsub
|
|
|
190
178
|
|
|
191
179
|
# Create backend connection
|
|
192
180
|
try:
|
|
193
|
-
backend =
|
|
181
|
+
backend = get_async_pubsub(**pubsub_config)
|
|
194
182
|
except Exception as e:
|
|
195
183
|
print(f"Error connecting to backend: {e}", file=sys.stderr)
|
|
196
184
|
sys.exit(1)
|
|
197
185
|
|
|
198
|
-
# Create
|
|
186
|
+
# Create consumers and central queue
|
|
199
187
|
central_queue = asyncio.Queue()
|
|
200
|
-
|
|
188
|
+
consumers = []
|
|
201
189
|
|
|
202
190
|
for queue_name in queues:
|
|
203
191
|
try:
|
|
204
|
-
|
|
205
|
-
backend=backend,
|
|
192
|
+
consumer = await backend.create_consumer(
|
|
206
193
|
topic=queue_name,
|
|
207
194
|
subscription=subscriber_name,
|
|
208
|
-
|
|
209
|
-
|
|
195
|
+
schema=None,
|
|
196
|
+
initial_position='latest',
|
|
210
197
|
)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
print(f"✓ Subscribed to: {queue_name}")
|
|
198
|
+
consumers.append((queue_name, consumer))
|
|
199
|
+
print(f" Subscribed to: {queue_name}")
|
|
214
200
|
except Exception as e:
|
|
215
|
-
print(f"
|
|
201
|
+
print(f" Error subscribing to {queue_name}: {e}", file=sys.stderr)
|
|
216
202
|
|
|
217
|
-
if not
|
|
218
|
-
print("\nNo
|
|
219
|
-
backend.close()
|
|
203
|
+
if not consumers:
|
|
204
|
+
print("\nNo consumers created. Exiting.", file=sys.stderr)
|
|
205
|
+
await backend.close()
|
|
220
206
|
sys.exit(1)
|
|
221
207
|
|
|
222
208
|
print(f"\nListening for messages...\n")
|
|
@@ -237,10 +223,10 @@ async def async_main(queues, output_file, subscriber_name, append_mode, **pubsub
|
|
|
237
223
|
# Start monitoring tasks
|
|
238
224
|
tasks = []
|
|
239
225
|
try:
|
|
240
|
-
# Create one monitor task per
|
|
241
|
-
for queue_name,
|
|
226
|
+
# Create one monitor task per consumer
|
|
227
|
+
for queue_name, consumer in consumers:
|
|
242
228
|
task = asyncio.create_task(
|
|
243
|
-
monitor_queue(
|
|
229
|
+
monitor_queue(consumer, queue_name, central_queue, shutdown_event)
|
|
244
230
|
)
|
|
245
231
|
tasks.append(task)
|
|
246
232
|
|
|
@@ -274,17 +260,20 @@ async def async_main(queues, output_file, subscriber_name, append_mode, **pubsub
|
|
|
274
260
|
print(f"Error writing to {output_file}: {e}", file=sys.stderr)
|
|
275
261
|
sys.exit(1)
|
|
276
262
|
finally:
|
|
277
|
-
# Clean shutdown of
|
|
278
|
-
for _,
|
|
279
|
-
|
|
280
|
-
|
|
263
|
+
# Clean shutdown of consumers
|
|
264
|
+
for _, consumer in consumers:
|
|
265
|
+
try:
|
|
266
|
+
await consumer.close()
|
|
267
|
+
except Exception:
|
|
268
|
+
pass
|
|
269
|
+
await backend.close()
|
|
281
270
|
|
|
282
271
|
print(f"\nMessages logged to: {output_file}")
|
|
283
272
|
|
|
284
273
|
def main():
|
|
285
274
|
parser = argparse.ArgumentParser(
|
|
286
275
|
prog='tg-dump-queues',
|
|
287
|
-
description='Monitor and dump messages from multiple
|
|
276
|
+
description='Monitor and dump messages from multiple queues',
|
|
288
277
|
epilog="""
|
|
289
278
|
Examples:
|
|
290
279
|
# Monitor agent and prompt flow queues
|
|
@@ -308,7 +297,7 @@ IMPORTANT:
|
|
|
308
297
|
before running this tool. If this tool subscribes first, the real services may
|
|
309
298
|
encounter schema mismatch errors when they try to connect.
|
|
310
299
|
|
|
311
|
-
Best practice: Start services
|
|
300
|
+
Best practice: Start services -> Set up flows -> Run tg-dump-queues
|
|
312
301
|
""",
|
|
313
302
|
formatter_class=argparse.RawDescriptionHelpFormatter
|
|
314
303
|
)
|
|
@@ -316,7 +305,7 @@ IMPORTANT:
|
|
|
316
305
|
parser.add_argument(
|
|
317
306
|
'queues',
|
|
318
307
|
nargs='+',
|
|
319
|
-
help='
|
|
308
|
+
help='Queue names to monitor'
|
|
320
309
|
)
|
|
321
310
|
|
|
322
311
|
parser.add_argument(
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Monitor prompt request/response queues and log activity with timing.
|
|
3
|
+
|
|
4
|
+
Subscribes to prompt request and response queues, correlates
|
|
5
|
+
them by message ID, and logs a summary of each request/response with
|
|
6
|
+
elapsed time. Streaming responses are accumulated and shown once at
|
|
7
|
+
completion.
|
|
8
|
+
|
|
9
|
+
Examples:
|
|
10
|
+
tg-monitor-prompts
|
|
11
|
+
tg-monitor-prompts --flow default --max-lines 5
|
|
12
|
+
tg-monitor-prompts --queue-type prompt-rag
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import asyncio
|
|
17
|
+
import sys
|
|
18
|
+
import argparse
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
from collections import OrderedDict
|
|
21
|
+
|
|
22
|
+
from trustgraph.base.pubsub import get_async_pubsub, add_pubsub_args
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
default_flow = "default"
|
|
26
|
+
default_queue_type = "prompt-rag"
|
|
27
|
+
default_max_lines = 3
|
|
28
|
+
default_max_width = 80
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def truncate_text(text, max_lines, max_width):
|
|
32
|
+
"""Truncate text to max_lines lines, each at most max_width chars."""
|
|
33
|
+
if not text:
|
|
34
|
+
return "(empty)"
|
|
35
|
+
|
|
36
|
+
lines = text.splitlines()
|
|
37
|
+
result = []
|
|
38
|
+
for line in lines[:max_lines]:
|
|
39
|
+
if len(line) > max_width:
|
|
40
|
+
result.append(line[:max_width - 3] + "...")
|
|
41
|
+
else:
|
|
42
|
+
result.append(line)
|
|
43
|
+
|
|
44
|
+
if len(lines) > max_lines:
|
|
45
|
+
result.append(f" ... ({len(lines) - max_lines} more lines)")
|
|
46
|
+
|
|
47
|
+
return "\n".join(result)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def summarise_value(value, max_width):
|
|
51
|
+
"""Summarise a term value -- show type and size for large values."""
|
|
52
|
+
# Try to parse JSON
|
|
53
|
+
try:
|
|
54
|
+
parsed = json.loads(value)
|
|
55
|
+
except (json.JSONDecodeError, TypeError):
|
|
56
|
+
parsed = value
|
|
57
|
+
|
|
58
|
+
if isinstance(parsed, list):
|
|
59
|
+
return f"[{len(parsed)} items]"
|
|
60
|
+
elif isinstance(parsed, dict):
|
|
61
|
+
return f"{{{len(parsed)} keys}}"
|
|
62
|
+
elif isinstance(parsed, str):
|
|
63
|
+
if len(parsed) > max_width:
|
|
64
|
+
return parsed[:max_width - 3] + "..."
|
|
65
|
+
return parsed
|
|
66
|
+
else:
|
|
67
|
+
s = str(parsed)
|
|
68
|
+
if len(s) > max_width:
|
|
69
|
+
return s[:max_width - 3] + "..."
|
|
70
|
+
return s
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def format_terms(terms, max_lines, max_width):
|
|
74
|
+
"""Format prompt terms for display -- concise summary."""
|
|
75
|
+
if not terms:
|
|
76
|
+
return ""
|
|
77
|
+
|
|
78
|
+
parts = []
|
|
79
|
+
for key, value in terms.items():
|
|
80
|
+
summary = summarise_value(value, max_width - len(key) - 4)
|
|
81
|
+
parts.append(f" {key}: {summary}")
|
|
82
|
+
|
|
83
|
+
return "\n".join(parts)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def parse_raw_message(msg):
|
|
87
|
+
"""Parse a raw message into (correlation_id, body_dict)."""
|
|
88
|
+
try:
|
|
89
|
+
props = msg.properties()
|
|
90
|
+
corr_id = props.get("id", "")
|
|
91
|
+
except Exception:
|
|
92
|
+
corr_id = ""
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
value = msg.value()
|
|
96
|
+
if isinstance(value, dict):
|
|
97
|
+
body = value
|
|
98
|
+
elif isinstance(value, bytes):
|
|
99
|
+
body = json.loads(value.decode("utf-8"))
|
|
100
|
+
elif isinstance(value, str):
|
|
101
|
+
body = json.loads(value)
|
|
102
|
+
else:
|
|
103
|
+
body = {}
|
|
104
|
+
except Exception:
|
|
105
|
+
body = {}
|
|
106
|
+
|
|
107
|
+
return corr_id, body
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
async def poll_consumer(consumer, queue_label, handler, shutdown_event):
|
|
111
|
+
"""Poll a single consumer and call handler for each message."""
|
|
112
|
+
while not shutdown_event.is_set():
|
|
113
|
+
try:
|
|
114
|
+
msg = await asyncio.wait_for(consumer.receive(), timeout=0.1)
|
|
115
|
+
await handler(msg)
|
|
116
|
+
await consumer.acknowledge(msg)
|
|
117
|
+
except asyncio.TimeoutError:
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def monitor(flow, queue_type, max_lines, max_width, **config):
|
|
122
|
+
|
|
123
|
+
request_queue = f"request:tg:{queue_type}:{flow}"
|
|
124
|
+
response_queue = f"response:tg:{queue_type}:{flow}"
|
|
125
|
+
|
|
126
|
+
print(f"Monitoring prompt queues:")
|
|
127
|
+
print(f" Request: {request_queue}")
|
|
128
|
+
print(f" Response: {response_queue}")
|
|
129
|
+
print(f"Press Ctrl+C to stop\n")
|
|
130
|
+
|
|
131
|
+
backend = get_async_pubsub(**config)
|
|
132
|
+
|
|
133
|
+
req_consumer = await backend.create_consumer(
|
|
134
|
+
topic=request_queue,
|
|
135
|
+
subscription="prompt-monitor-req",
|
|
136
|
+
schema=None,
|
|
137
|
+
initial_position='latest',
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
resp_consumer = await backend.create_consumer(
|
|
141
|
+
topic=response_queue,
|
|
142
|
+
subscription="prompt-monitor-resp",
|
|
143
|
+
schema=None,
|
|
144
|
+
initial_position='latest',
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Track in-flight requests: corr_id -> (timestamp, template_id)
|
|
148
|
+
in_flight = OrderedDict()
|
|
149
|
+
|
|
150
|
+
# Accumulate streaming responses: corr_id -> list of text chunks
|
|
151
|
+
streaming_chunks = {}
|
|
152
|
+
|
|
153
|
+
print("Listening...\n")
|
|
154
|
+
|
|
155
|
+
shutdown_event = asyncio.Event()
|
|
156
|
+
|
|
157
|
+
async def handle_request(msg):
|
|
158
|
+
timestamp = datetime.now()
|
|
159
|
+
corr_id, body = parse_raw_message(msg)
|
|
160
|
+
time_str = timestamp.strftime("%H:%M:%S.%f")[:-3]
|
|
161
|
+
|
|
162
|
+
template_id = body.get("id", "(unknown)")
|
|
163
|
+
terms = body.get("terms", {})
|
|
164
|
+
streaming = body.get("streaming", False)
|
|
165
|
+
|
|
166
|
+
in_flight[corr_id] = (timestamp, template_id)
|
|
167
|
+
|
|
168
|
+
# Limit size
|
|
169
|
+
while len(in_flight) > 1000:
|
|
170
|
+
in_flight.popitem(last=False)
|
|
171
|
+
|
|
172
|
+
stream_flag = " [streaming]" if streaming else ""
|
|
173
|
+
id_display = corr_id[:8] if corr_id else "--------"
|
|
174
|
+
print(f"[{time_str}] REQ {id_display} "
|
|
175
|
+
f"template={template_id}{stream_flag}")
|
|
176
|
+
|
|
177
|
+
if terms:
|
|
178
|
+
print(format_terms(terms, max_lines, max_width))
|
|
179
|
+
|
|
180
|
+
async def handle_response(msg):
|
|
181
|
+
timestamp = datetime.now()
|
|
182
|
+
corr_id, body = parse_raw_message(msg)
|
|
183
|
+
time_str = timestamp.strftime("%H:%M:%S.%f")[:-3]
|
|
184
|
+
id_display = corr_id[:8] if corr_id else "--------"
|
|
185
|
+
|
|
186
|
+
error = body.get("error")
|
|
187
|
+
text = body.get("text", "")
|
|
188
|
+
obj = body.get("object", "")
|
|
189
|
+
eos = body.get("end_of_stream", False)
|
|
190
|
+
|
|
191
|
+
if error:
|
|
192
|
+
# Error -- show immediately
|
|
193
|
+
elapsed_str = ""
|
|
194
|
+
if corr_id in in_flight:
|
|
195
|
+
req_timestamp, _ = in_flight.pop(corr_id)
|
|
196
|
+
elapsed = (timestamp - req_timestamp).total_seconds()
|
|
197
|
+
elapsed_str = f" ({elapsed:.3f}s)"
|
|
198
|
+
streaming_chunks.pop(corr_id, None)
|
|
199
|
+
|
|
200
|
+
err_msg = error
|
|
201
|
+
if isinstance(error, dict):
|
|
202
|
+
err_msg = error.get("message", str(error))
|
|
203
|
+
print(f"[{time_str}] ERR {id_display} "
|
|
204
|
+
f"{err_msg}{elapsed_str}")
|
|
205
|
+
|
|
206
|
+
elif eos:
|
|
207
|
+
# End of stream -- show accumulated text + timing
|
|
208
|
+
elapsed_str = ""
|
|
209
|
+
if corr_id in in_flight:
|
|
210
|
+
req_timestamp, _ = in_flight.pop(corr_id)
|
|
211
|
+
elapsed = (timestamp - req_timestamp).total_seconds()
|
|
212
|
+
elapsed_str = f" ({elapsed:.3f}s)"
|
|
213
|
+
|
|
214
|
+
accumulated = streaming_chunks.pop(corr_id, [])
|
|
215
|
+
if text:
|
|
216
|
+
accumulated.append(text)
|
|
217
|
+
|
|
218
|
+
full_text = "".join(accumulated)
|
|
219
|
+
if full_text:
|
|
220
|
+
truncated = truncate_text(
|
|
221
|
+
full_text, max_lines, max_width
|
|
222
|
+
)
|
|
223
|
+
print(f"[{time_str}] RESP {id_display}"
|
|
224
|
+
f"{elapsed_str}")
|
|
225
|
+
print(f" {truncated}")
|
|
226
|
+
else:
|
|
227
|
+
print(f"[{time_str}] RESP {id_display}"
|
|
228
|
+
f"{elapsed_str} (empty)")
|
|
229
|
+
|
|
230
|
+
elif text or obj:
|
|
231
|
+
# Streaming chunk or non-streaming response
|
|
232
|
+
if corr_id in streaming_chunks or (
|
|
233
|
+
corr_id in in_flight
|
|
234
|
+
):
|
|
235
|
+
# Accumulate streaming chunk
|
|
236
|
+
if corr_id not in streaming_chunks:
|
|
237
|
+
streaming_chunks[corr_id] = []
|
|
238
|
+
streaming_chunks[corr_id].append(text or obj)
|
|
239
|
+
else:
|
|
240
|
+
# Non-streaming single response
|
|
241
|
+
elapsed_str = ""
|
|
242
|
+
if corr_id in in_flight:
|
|
243
|
+
req_timestamp, _ = in_flight.pop(corr_id)
|
|
244
|
+
elapsed = (
|
|
245
|
+
timestamp - req_timestamp
|
|
246
|
+
).total_seconds()
|
|
247
|
+
elapsed_str = f" ({elapsed:.3f}s)"
|
|
248
|
+
|
|
249
|
+
content = text or obj
|
|
250
|
+
label = "" if text else " (object)"
|
|
251
|
+
truncated = truncate_text(
|
|
252
|
+
content, max_lines, max_width
|
|
253
|
+
)
|
|
254
|
+
print(f"[{time_str}] RESP {id_display}"
|
|
255
|
+
f"{label}{elapsed_str}")
|
|
256
|
+
print(f" {truncated}")
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
await asyncio.gather(
|
|
260
|
+
poll_consumer(
|
|
261
|
+
req_consumer, "request", handle_request, shutdown_event,
|
|
262
|
+
),
|
|
263
|
+
poll_consumer(
|
|
264
|
+
resp_consumer, "response", handle_response, shutdown_event,
|
|
265
|
+
),
|
|
266
|
+
)
|
|
267
|
+
except KeyboardInterrupt:
|
|
268
|
+
print("\nStopping...")
|
|
269
|
+
finally:
|
|
270
|
+
shutdown_event.set()
|
|
271
|
+
await req_consumer.close()
|
|
272
|
+
await resp_consumer.close()
|
|
273
|
+
await backend.close()
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def main():
|
|
277
|
+
parser = argparse.ArgumentParser(
|
|
278
|
+
prog="tg-monitor-prompts",
|
|
279
|
+
description=__doc__,
|
|
280
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
parser.add_argument(
|
|
284
|
+
"-f", "--flow",
|
|
285
|
+
default=default_flow,
|
|
286
|
+
help=f"Flow ID (default: {default_flow})",
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
parser.add_argument(
|
|
290
|
+
"-q", "--queue-type",
|
|
291
|
+
default=default_queue_type,
|
|
292
|
+
help=f"Queue type: prompt or prompt-rag (default: {default_queue_type})",
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
parser.add_argument(
|
|
296
|
+
"-l", "--max-lines",
|
|
297
|
+
type=int,
|
|
298
|
+
default=default_max_lines,
|
|
299
|
+
help=f"Max lines of text per term/response (default: {default_max_lines})",
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
parser.add_argument(
|
|
303
|
+
"-w", "--max-width",
|
|
304
|
+
type=int,
|
|
305
|
+
default=default_max_width,
|
|
306
|
+
help=f"Max width per line (default: {default_max_width})",
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
add_pubsub_args(parser, standalone=True)
|
|
310
|
+
|
|
311
|
+
args = parser.parse_args()
|
|
312
|
+
|
|
313
|
+
try:
|
|
314
|
+
asyncio.run(monitor(
|
|
315
|
+
flow=args.flow,
|
|
316
|
+
queue_type=args.queue_type,
|
|
317
|
+
max_lines=args.max_lines,
|
|
318
|
+
max_width=args.max_width,
|
|
319
|
+
**{k: v for k, v in vars(args).items()
|
|
320
|
+
if k not in ('flow', 'queue_type', 'max_lines', 'max_width')},
|
|
321
|
+
))
|
|
322
|
+
except KeyboardInterrupt:
|
|
323
|
+
pass
|
|
324
|
+
except Exception as e:
|
|
325
|
+
print(f"Fatal error: {e}", file=sys.stderr)
|
|
326
|
+
sys.exit(1)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
if __name__ == "__main__":
|
|
330
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.8.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trustgraph-cli
|
|
3
|
-
Version: 2.8.
|
|
3
|
+
Version: 2.8.2
|
|
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
|