trustgraph-cli 2.2.2__tar.gz → 2.2.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.
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/PKG-INFO +1 -1
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/list_explain_traces.py +12 -10
- trustgraph_cli-2.2.4/trustgraph/cli/show_flow_blueprints.py +173 -0
- trustgraph_cli-2.2.4/trustgraph/cli/show_flows.py +286 -0
- trustgraph_cli-2.2.4/trustgraph/cli/show_parameter_types.py +213 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/verify_system_status.py +5 -1
- trustgraph_cli-2.2.4/trustgraph/cli_version.py +1 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/PKG-INFO +1 -1
- trustgraph_cli-2.2.2/trustgraph/cli/show_flow_blueprints.py +0 -130
- trustgraph_cli-2.2.2/trustgraph/cli/show_flows.py +0 -223
- trustgraph_cli-2.2.2/trustgraph/cli/show_parameter_types.py +0 -217
- trustgraph_cli-2.2.2/trustgraph/cli_version.py +0 -1
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/README.md +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/pyproject.toml +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/setup.cfg +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/__init__.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/add_library_document.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_collection.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_config_item.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_flow_blueprint.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_kg_core.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_mcp_tool.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_tool.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/dump_msgpack.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/dump_queues.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/get_config_item.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/get_document_content.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/get_flow_blueprint.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/get_kg_core.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/graph_to_turtle.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/init_pulsar_manager.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/init_trustgraph.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_agent.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_document_embeddings.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_document_rag.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_embeddings.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_graph_embeddings.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_graph_rag.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_llm.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_mcp_tool.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_nlp_query.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_prompt.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_row_embeddings.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_rows_query.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_structured_query.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/list_collections.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/list_config_items.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/load_doc_embeds.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/load_kg_core.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/load_knowledge.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/load_sample_documents.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/load_structured_data.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/load_turtle.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/put_config_item.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/put_flow_blueprint.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/put_kg_core.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/query_graph.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/remove_library_document.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/save_doc_embeds.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/set_collection.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/set_mcp_tool.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/set_prompt.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/set_token_costs.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/set_tool.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_config.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_explain_trace.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_extraction_provenance.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_flow_state.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_graph.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_kg_cores.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_library_documents.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_library_processing.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_mcp_tools.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_processor_state.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_prompts.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_token_costs.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_token_rate.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/show_tools.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/start_flow.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/start_library_processing.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/stop_flow.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/stop_library_processing.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph/cli/unload_kg_core.py +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/SOURCES.txt +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/dependency_links.txt +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/entry_points.txt +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/requires.txt +0 -0
- {trustgraph_cli-2.2.2 → trustgraph_cli-2.2.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: 2.2.
|
|
3
|
+
Version: 2.2.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
|
|
@@ -58,6 +58,14 @@ def print_json(sessions):
|
|
|
58
58
|
print(json.dumps(sessions, indent=2))
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
# Map type names for display
|
|
62
|
+
TYPE_DISPLAY = {
|
|
63
|
+
"graphrag": "GraphRAG",
|
|
64
|
+
"docrag": "DocRAG",
|
|
65
|
+
"agent": "Agent",
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
61
69
|
def main():
|
|
62
70
|
parser = argparse.ArgumentParser(
|
|
63
71
|
prog='tg-list-explain-traces',
|
|
@@ -118,7 +126,7 @@ def main():
|
|
|
118
126
|
explain_client = ExplainabilityClient(flow)
|
|
119
127
|
|
|
120
128
|
try:
|
|
121
|
-
# List all sessions
|
|
129
|
+
# List all sessions — uses persistent websocket via SocketClient
|
|
122
130
|
questions = explain_client.list_sessions(
|
|
123
131
|
graph=RETRIEVAL_GRAPH,
|
|
124
132
|
user=args.user,
|
|
@@ -126,7 +134,8 @@ def main():
|
|
|
126
134
|
limit=args.limit,
|
|
127
135
|
)
|
|
128
136
|
|
|
129
|
-
#
|
|
137
|
+
# detect_session_type is mostly a fast URI pattern check,
|
|
138
|
+
# only falls back to network calls for unrecognised URIs
|
|
130
139
|
sessions = []
|
|
131
140
|
for q in questions:
|
|
132
141
|
session_type = explain_client.detect_session_type(
|
|
@@ -136,16 +145,9 @@ def main():
|
|
|
136
145
|
collection=args.collection
|
|
137
146
|
)
|
|
138
147
|
|
|
139
|
-
# Map type names
|
|
140
|
-
type_display = {
|
|
141
|
-
"graphrag": "GraphRAG",
|
|
142
|
-
"docrag": "DocRAG",
|
|
143
|
-
"agent": "Agent",
|
|
144
|
-
}.get(session_type, session_type.title())
|
|
145
|
-
|
|
146
148
|
sessions.append({
|
|
147
149
|
"id": q.uri,
|
|
148
|
-
"type":
|
|
150
|
+
"type": TYPE_DISPLAY.get(session_type, session_type.title()),
|
|
149
151
|
"question": q.query,
|
|
150
152
|
"time": q.timestamp,
|
|
151
153
|
})
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shows all defined flow blueprints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import os
|
|
8
|
+
import tabulate
|
|
9
|
+
from trustgraph.api import AsyncSocketClient
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
|
|
13
|
+
default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
|
|
14
|
+
|
|
15
|
+
def format_parameters(params_metadata, param_type_defs):
|
|
16
|
+
"""
|
|
17
|
+
Format parameter metadata for display.
|
|
18
|
+
|
|
19
|
+
param_type_defs is a dict of type_name -> parsed type definition,
|
|
20
|
+
pre-fetched concurrently.
|
|
21
|
+
"""
|
|
22
|
+
if not params_metadata:
|
|
23
|
+
return "None"
|
|
24
|
+
|
|
25
|
+
param_list = []
|
|
26
|
+
|
|
27
|
+
sorted_params = sorted(
|
|
28
|
+
params_metadata.items(),
|
|
29
|
+
key=lambda x: x[1].get("order", 999)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
for param_name, param_meta in sorted_params:
|
|
33
|
+
description = param_meta.get("description", param_name)
|
|
34
|
+
param_type = param_meta.get("type", "unknown")
|
|
35
|
+
|
|
36
|
+
type_info = param_type
|
|
37
|
+
if param_type in param_type_defs:
|
|
38
|
+
param_type_def = param_type_defs[param_type]
|
|
39
|
+
default = param_type_def.get("default")
|
|
40
|
+
if default is not None:
|
|
41
|
+
type_info = f"{param_type} (default: {default})"
|
|
42
|
+
|
|
43
|
+
param_list.append(f" {param_name}: {description} [{type_info}]")
|
|
44
|
+
|
|
45
|
+
return "\n".join(param_list)
|
|
46
|
+
|
|
47
|
+
async def fetch_data(client):
|
|
48
|
+
"""Fetch all data needed for show_flow_blueprints concurrently."""
|
|
49
|
+
|
|
50
|
+
# Round 1: list blueprints
|
|
51
|
+
resp = await client._send_request("flow", None, {
|
|
52
|
+
"operation": "list-blueprints",
|
|
53
|
+
})
|
|
54
|
+
blueprint_names = resp.get("blueprint-names", [])
|
|
55
|
+
|
|
56
|
+
if not blueprint_names:
|
|
57
|
+
return [], {}, {}
|
|
58
|
+
|
|
59
|
+
# Round 2: get all blueprints in parallel
|
|
60
|
+
blueprint_tasks = [
|
|
61
|
+
client._send_request("flow", None, {
|
|
62
|
+
"operation": "get-blueprint",
|
|
63
|
+
"blueprint-name": name,
|
|
64
|
+
})
|
|
65
|
+
for name in blueprint_names
|
|
66
|
+
]
|
|
67
|
+
blueprint_results = await asyncio.gather(*blueprint_tasks)
|
|
68
|
+
|
|
69
|
+
blueprints = {}
|
|
70
|
+
for name, resp in zip(blueprint_names, blueprint_results):
|
|
71
|
+
bp_data = resp.get("blueprint-definition", "{}")
|
|
72
|
+
blueprints[name] = json.loads(bp_data) if isinstance(bp_data, str) else bp_data
|
|
73
|
+
|
|
74
|
+
# Round 3: get all parameter type definitions in parallel
|
|
75
|
+
param_types_needed = set()
|
|
76
|
+
for bp in blueprints.values():
|
|
77
|
+
for param_meta in bp.get("parameters", {}).values():
|
|
78
|
+
pt = param_meta.get("type", "")
|
|
79
|
+
if pt:
|
|
80
|
+
param_types_needed.add(pt)
|
|
81
|
+
|
|
82
|
+
param_type_defs = {}
|
|
83
|
+
if param_types_needed:
|
|
84
|
+
param_type_tasks = [
|
|
85
|
+
client._send_request("config", None, {
|
|
86
|
+
"operation": "get",
|
|
87
|
+
"keys": [{"type": "parameter-type", "key": pt}],
|
|
88
|
+
})
|
|
89
|
+
for pt in param_types_needed
|
|
90
|
+
]
|
|
91
|
+
param_type_results = await asyncio.gather(*param_type_tasks)
|
|
92
|
+
|
|
93
|
+
for pt, resp in zip(param_types_needed, param_type_results):
|
|
94
|
+
values = resp.get("values", [])
|
|
95
|
+
if values:
|
|
96
|
+
try:
|
|
97
|
+
param_type_defs[pt] = json.loads(values[0].get("value", "{}"))
|
|
98
|
+
except (json.JSONDecodeError, AttributeError):
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
return blueprint_names, blueprints, param_type_defs
|
|
102
|
+
|
|
103
|
+
async def _show_flow_blueprints_async(url, token=None):
|
|
104
|
+
async with AsyncSocketClient(url, timeout=60, token=token) as client:
|
|
105
|
+
return await fetch_data(client)
|
|
106
|
+
|
|
107
|
+
def show_flow_blueprints(url, token=None):
|
|
108
|
+
|
|
109
|
+
blueprint_names, blueprints, param_type_defs = asyncio.run(
|
|
110
|
+
_show_flow_blueprints_async(url, token=token)
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if not blueprint_names:
|
|
114
|
+
print("No flow blueprints.")
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
for blueprint_name in blueprint_names:
|
|
118
|
+
cls = blueprints[blueprint_name]
|
|
119
|
+
|
|
120
|
+
table = []
|
|
121
|
+
table.append(("name", blueprint_name))
|
|
122
|
+
table.append(("description", cls.get("description", "")))
|
|
123
|
+
|
|
124
|
+
tags = cls.get("tags", [])
|
|
125
|
+
if tags:
|
|
126
|
+
table.append(("tags", ", ".join(tags)))
|
|
127
|
+
|
|
128
|
+
parameters = cls.get("parameters", {})
|
|
129
|
+
if parameters:
|
|
130
|
+
param_str = format_parameters(parameters, param_type_defs)
|
|
131
|
+
table.append(("parameters", param_str))
|
|
132
|
+
|
|
133
|
+
print(tabulate.tabulate(
|
|
134
|
+
table,
|
|
135
|
+
tablefmt="pretty",
|
|
136
|
+
stralign="left",
|
|
137
|
+
))
|
|
138
|
+
print()
|
|
139
|
+
|
|
140
|
+
def main():
|
|
141
|
+
|
|
142
|
+
parser = argparse.ArgumentParser(
|
|
143
|
+
prog='tg-show-flow-blueprints',
|
|
144
|
+
description=__doc__,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
parser.add_argument(
|
|
148
|
+
'-u', '--api-url',
|
|
149
|
+
default=default_url,
|
|
150
|
+
help=f'API URL (default: {default_url})',
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
'-t', '--token',
|
|
155
|
+
default=default_token,
|
|
156
|
+
help='Authentication token (default: $TRUSTGRAPH_TOKEN)',
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
args = parser.parse_args()
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
|
|
163
|
+
show_flow_blueprints(
|
|
164
|
+
url=args.api_url,
|
|
165
|
+
token=args.token,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
|
|
170
|
+
print("Exception:", e, flush=True)
|
|
171
|
+
|
|
172
|
+
if __name__ == "__main__":
|
|
173
|
+
main()
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shows configured flows.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import os
|
|
8
|
+
import tabulate
|
|
9
|
+
from trustgraph.api import Api, AsyncSocketClient
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
|
|
13
|
+
default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
|
|
14
|
+
|
|
15
|
+
def describe_interfaces(intdefs, flow):
|
|
16
|
+
|
|
17
|
+
intfs = flow.get("interfaces", {})
|
|
18
|
+
|
|
19
|
+
lst = []
|
|
20
|
+
|
|
21
|
+
for k, v in intdefs.items():
|
|
22
|
+
|
|
23
|
+
if intdefs[k].get("visible", False):
|
|
24
|
+
|
|
25
|
+
label = intdefs[k].get("description", k)
|
|
26
|
+
kind = intdefs[k].get("kind", None)
|
|
27
|
+
|
|
28
|
+
if kind == "request-response":
|
|
29
|
+
req = intfs[k]["request"]
|
|
30
|
+
resp = intfs[k]["response"]
|
|
31
|
+
|
|
32
|
+
lst.append(f"{k} request: {req}")
|
|
33
|
+
lst.append(f"{k} response: {resp}")
|
|
34
|
+
|
|
35
|
+
if kind == "send":
|
|
36
|
+
q = intfs[k]
|
|
37
|
+
|
|
38
|
+
lst.append(f"{k}: {q}")
|
|
39
|
+
|
|
40
|
+
return "\n".join(lst)
|
|
41
|
+
|
|
42
|
+
def get_enum_description(param_value, param_type_def):
|
|
43
|
+
"""
|
|
44
|
+
Get the human-readable description for an enum value
|
|
45
|
+
"""
|
|
46
|
+
enum_list = param_type_def.get("enum", [])
|
|
47
|
+
|
|
48
|
+
for enum_item in enum_list:
|
|
49
|
+
if isinstance(enum_item, dict):
|
|
50
|
+
if enum_item.get("id") == param_value:
|
|
51
|
+
return enum_item.get("description", param_value)
|
|
52
|
+
elif enum_item == param_value:
|
|
53
|
+
return param_value
|
|
54
|
+
|
|
55
|
+
return param_value
|
|
56
|
+
|
|
57
|
+
def format_parameters(flow_params, blueprint_params_metadata, param_type_defs):
|
|
58
|
+
"""
|
|
59
|
+
Format flow parameters with their human-readable descriptions.
|
|
60
|
+
|
|
61
|
+
param_type_defs is a dict of type_name -> parsed type definition,
|
|
62
|
+
pre-fetched concurrently.
|
|
63
|
+
"""
|
|
64
|
+
if not flow_params:
|
|
65
|
+
return "None"
|
|
66
|
+
|
|
67
|
+
param_list = []
|
|
68
|
+
|
|
69
|
+
sorted_params = sorted(
|
|
70
|
+
blueprint_params_metadata.items(),
|
|
71
|
+
key=lambda x: x[1].get("order", 999)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
for param_name, param_meta in sorted_params:
|
|
75
|
+
if param_name in flow_params:
|
|
76
|
+
value = flow_params[param_name]
|
|
77
|
+
description = param_meta.get("description", param_name)
|
|
78
|
+
param_type = param_meta.get("type", "")
|
|
79
|
+
controlled_by = param_meta.get("controlled-by", None)
|
|
80
|
+
|
|
81
|
+
display_value = value
|
|
82
|
+
if param_type and param_type in param_type_defs:
|
|
83
|
+
display_value = get_enum_description(
|
|
84
|
+
value, param_type_defs[param_type]
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
line = f"• {description}: {display_value}"
|
|
88
|
+
|
|
89
|
+
if controlled_by:
|
|
90
|
+
line += f" (controlled by {controlled_by})"
|
|
91
|
+
|
|
92
|
+
param_list.append(line)
|
|
93
|
+
|
|
94
|
+
for param_name, value in flow_params.items():
|
|
95
|
+
if param_name not in blueprint_params_metadata:
|
|
96
|
+
param_list.append(f"• {param_name}: {value} (undefined)")
|
|
97
|
+
|
|
98
|
+
return "\n".join(param_list) if param_list else "None"
|
|
99
|
+
|
|
100
|
+
async def fetch_show_flows(client):
|
|
101
|
+
"""Fetch all data needed for show_flows concurrently."""
|
|
102
|
+
|
|
103
|
+
# Round 1: list interfaces and list flows in parallel
|
|
104
|
+
interface_names_resp, flow_ids_resp = await asyncio.gather(
|
|
105
|
+
client._send_request("config", None, {
|
|
106
|
+
"operation": "list",
|
|
107
|
+
"type": "interface-description",
|
|
108
|
+
}),
|
|
109
|
+
client._send_request("flow", None, {
|
|
110
|
+
"operation": "list-flows",
|
|
111
|
+
}),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
interface_names = interface_names_resp.get("directory", [])
|
|
115
|
+
flow_ids = flow_ids_resp.get("flow-ids", [])
|
|
116
|
+
|
|
117
|
+
if not flow_ids:
|
|
118
|
+
return {}, [], {}, {}
|
|
119
|
+
|
|
120
|
+
# Round 2: get all interfaces + all flows in parallel
|
|
121
|
+
interface_tasks = [
|
|
122
|
+
client._send_request("config", None, {
|
|
123
|
+
"operation": "get",
|
|
124
|
+
"keys": [{"type": "interface-description", "key": name}],
|
|
125
|
+
})
|
|
126
|
+
for name in interface_names
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
flow_tasks = [
|
|
130
|
+
client._send_request("flow", None, {
|
|
131
|
+
"operation": "get-flow",
|
|
132
|
+
"flow-id": fid,
|
|
133
|
+
})
|
|
134
|
+
for fid in flow_ids
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
results = await asyncio.gather(*interface_tasks, *flow_tasks)
|
|
138
|
+
|
|
139
|
+
# Split results
|
|
140
|
+
interface_results = results[:len(interface_names)]
|
|
141
|
+
flow_results = results[len(interface_names):]
|
|
142
|
+
|
|
143
|
+
# Parse interfaces
|
|
144
|
+
interface_defs = {}
|
|
145
|
+
for name, resp in zip(interface_names, interface_results):
|
|
146
|
+
values = resp.get("values", [])
|
|
147
|
+
if values:
|
|
148
|
+
interface_defs[name] = json.loads(values[0].get("value", "{}"))
|
|
149
|
+
|
|
150
|
+
# Parse flows
|
|
151
|
+
flows = {}
|
|
152
|
+
for fid, resp in zip(flow_ids, flow_results):
|
|
153
|
+
flow_data = resp.get("flow", "{}")
|
|
154
|
+
flows[fid] = json.loads(flow_data) if isinstance(flow_data, str) else flow_data
|
|
155
|
+
|
|
156
|
+
# Round 3: get all blueprints in parallel
|
|
157
|
+
blueprint_names = set()
|
|
158
|
+
for flow in flows.values():
|
|
159
|
+
bp = flow.get("blueprint-name", "")
|
|
160
|
+
if bp:
|
|
161
|
+
blueprint_names.add(bp)
|
|
162
|
+
|
|
163
|
+
blueprint_tasks = [
|
|
164
|
+
client._send_request("flow", None, {
|
|
165
|
+
"operation": "get-blueprint",
|
|
166
|
+
"blueprint-name": bp_name,
|
|
167
|
+
})
|
|
168
|
+
for bp_name in blueprint_names
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
blueprint_results = await asyncio.gather(*blueprint_tasks)
|
|
172
|
+
|
|
173
|
+
blueprints = {}
|
|
174
|
+
for bp_name, resp in zip(blueprint_names, blueprint_results):
|
|
175
|
+
bp_data = resp.get("blueprint-definition", "{}")
|
|
176
|
+
blueprints[bp_name] = json.loads(bp_data) if isinstance(bp_data, str) else bp_data
|
|
177
|
+
|
|
178
|
+
# Round 4: get all parameter type definitions in parallel
|
|
179
|
+
param_types_needed = set()
|
|
180
|
+
for bp in blueprints.values():
|
|
181
|
+
for param_meta in bp.get("parameters", {}).values():
|
|
182
|
+
pt = param_meta.get("type", "")
|
|
183
|
+
if pt:
|
|
184
|
+
param_types_needed.add(pt)
|
|
185
|
+
|
|
186
|
+
param_type_tasks = [
|
|
187
|
+
client._send_request("config", None, {
|
|
188
|
+
"operation": "get",
|
|
189
|
+
"keys": [{"type": "parameter-type", "key": pt}],
|
|
190
|
+
})
|
|
191
|
+
for pt in param_types_needed
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
param_type_results = await asyncio.gather(*param_type_tasks)
|
|
195
|
+
|
|
196
|
+
param_type_defs = {}
|
|
197
|
+
for pt, resp in zip(param_types_needed, param_type_results):
|
|
198
|
+
values = resp.get("values", [])
|
|
199
|
+
if values:
|
|
200
|
+
try:
|
|
201
|
+
param_type_defs[pt] = json.loads(values[0].get("value", "{}"))
|
|
202
|
+
except (json.JSONDecodeError, AttributeError):
|
|
203
|
+
pass
|
|
204
|
+
|
|
205
|
+
return interface_defs, flow_ids, flows, blueprints, param_type_defs
|
|
206
|
+
|
|
207
|
+
async def _show_flows_async(url, token=None):
|
|
208
|
+
|
|
209
|
+
async with AsyncSocketClient(url, timeout=60, token=token) as client:
|
|
210
|
+
return await fetch_show_flows(client)
|
|
211
|
+
|
|
212
|
+
def show_flows(url, token=None):
|
|
213
|
+
|
|
214
|
+
result = asyncio.run(_show_flows_async(url, token=token))
|
|
215
|
+
|
|
216
|
+
interface_defs, flow_ids, flows, blueprints, param_type_defs = result
|
|
217
|
+
|
|
218
|
+
if not flow_ids:
|
|
219
|
+
print("No flows.")
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
for fid in flow_ids:
|
|
223
|
+
|
|
224
|
+
flow = flows[fid]
|
|
225
|
+
|
|
226
|
+
table = []
|
|
227
|
+
table.append(("id", fid))
|
|
228
|
+
table.append(("blueprint", flow.get("blueprint-name", "")))
|
|
229
|
+
table.append(("desc", flow.get("description", "")))
|
|
230
|
+
|
|
231
|
+
parameters = flow.get("parameters", {})
|
|
232
|
+
if parameters:
|
|
233
|
+
blueprint_name = flow.get("blueprint-name", "")
|
|
234
|
+
if blueprint_name and blueprint_name in blueprints:
|
|
235
|
+
blueprint_params_metadata = blueprints[blueprint_name].get("parameters", {})
|
|
236
|
+
param_str = format_parameters(
|
|
237
|
+
parameters, blueprint_params_metadata, param_type_defs
|
|
238
|
+
)
|
|
239
|
+
else:
|
|
240
|
+
param_str = json.dumps(parameters, indent=2)
|
|
241
|
+
|
|
242
|
+
table.append(("parameters", param_str))
|
|
243
|
+
|
|
244
|
+
table.append(("queue", describe_interfaces(interface_defs, flow)))
|
|
245
|
+
|
|
246
|
+
print(tabulate.tabulate(
|
|
247
|
+
table,
|
|
248
|
+
tablefmt="pretty",
|
|
249
|
+
stralign="left",
|
|
250
|
+
))
|
|
251
|
+
print()
|
|
252
|
+
|
|
253
|
+
def main():
|
|
254
|
+
|
|
255
|
+
parser = argparse.ArgumentParser(
|
|
256
|
+
prog='tg-show-flows',
|
|
257
|
+
description=__doc__,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
parser.add_argument(
|
|
261
|
+
'-u', '--api-url',
|
|
262
|
+
default=default_url,
|
|
263
|
+
help=f'API URL (default: {default_url})',
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
parser.add_argument(
|
|
267
|
+
'-t', '--token',
|
|
268
|
+
default=default_token,
|
|
269
|
+
help='Authentication token (default: $TRUSTGRAPH_TOKEN)',
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
args = parser.parse_args()
|
|
273
|
+
|
|
274
|
+
try:
|
|
275
|
+
|
|
276
|
+
show_flows(
|
|
277
|
+
url=args.api_url,
|
|
278
|
+
token=args.token,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
|
|
283
|
+
print("Exception:", e, flush=True)
|
|
284
|
+
|
|
285
|
+
if __name__ == "__main__":
|
|
286
|
+
main()
|