trustgraph-cli 2.2.3__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.
Files changed (88) hide show
  1. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/PKG-INFO +1 -1
  2. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/list_explain_traces.py +12 -10
  3. trustgraph_cli-2.2.4/trustgraph/cli/show_flow_blueprints.py +173 -0
  4. trustgraph_cli-2.2.4/trustgraph/cli/show_flows.py +286 -0
  5. trustgraph_cli-2.2.4/trustgraph/cli/show_parameter_types.py +213 -0
  6. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/verify_system_status.py +5 -1
  7. trustgraph_cli-2.2.4/trustgraph/cli_version.py +1 -0
  8. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/PKG-INFO +1 -1
  9. trustgraph_cli-2.2.3/trustgraph/cli/show_flow_blueprints.py +0 -130
  10. trustgraph_cli-2.2.3/trustgraph/cli/show_flows.py +0 -223
  11. trustgraph_cli-2.2.3/trustgraph/cli/show_parameter_types.py +0 -217
  12. trustgraph_cli-2.2.3/trustgraph/cli_version.py +0 -1
  13. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/README.md +0 -0
  14. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/pyproject.toml +0 -0
  15. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/setup.cfg +0 -0
  16. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/__init__.py +0 -0
  17. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/add_library_document.py +0 -0
  18. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_collection.py +0 -0
  19. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_config_item.py +0 -0
  20. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_flow_blueprint.py +0 -0
  21. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_kg_core.py +0 -0
  22. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_mcp_tool.py +0 -0
  23. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/delete_tool.py +0 -0
  24. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/dump_msgpack.py +0 -0
  25. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/dump_queues.py +0 -0
  26. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/get_config_item.py +0 -0
  27. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/get_document_content.py +0 -0
  28. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/get_flow_blueprint.py +0 -0
  29. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/get_kg_core.py +0 -0
  30. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/graph_to_turtle.py +0 -0
  31. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/init_pulsar_manager.py +0 -0
  32. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/init_trustgraph.py +0 -0
  33. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_agent.py +0 -0
  34. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_document_embeddings.py +0 -0
  35. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_document_rag.py +0 -0
  36. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_embeddings.py +0 -0
  37. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_graph_embeddings.py +0 -0
  38. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_graph_rag.py +0 -0
  39. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_llm.py +0 -0
  40. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_mcp_tool.py +0 -0
  41. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_nlp_query.py +0 -0
  42. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_prompt.py +0 -0
  43. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_row_embeddings.py +0 -0
  44. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_rows_query.py +0 -0
  45. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/invoke_structured_query.py +0 -0
  46. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/list_collections.py +0 -0
  47. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/list_config_items.py +0 -0
  48. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/load_doc_embeds.py +0 -0
  49. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/load_kg_core.py +0 -0
  50. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/load_knowledge.py +0 -0
  51. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/load_sample_documents.py +0 -0
  52. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/load_structured_data.py +0 -0
  53. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/load_turtle.py +0 -0
  54. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/put_config_item.py +0 -0
  55. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/put_flow_blueprint.py +0 -0
  56. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/put_kg_core.py +0 -0
  57. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/query_graph.py +0 -0
  58. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/remove_library_document.py +0 -0
  59. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/save_doc_embeds.py +0 -0
  60. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/set_collection.py +0 -0
  61. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/set_mcp_tool.py +0 -0
  62. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/set_prompt.py +0 -0
  63. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/set_token_costs.py +0 -0
  64. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/set_tool.py +0 -0
  65. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_config.py +0 -0
  66. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_explain_trace.py +0 -0
  67. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_extraction_provenance.py +0 -0
  68. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_flow_state.py +0 -0
  69. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_graph.py +0 -0
  70. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_kg_cores.py +0 -0
  71. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_library_documents.py +0 -0
  72. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_library_processing.py +0 -0
  73. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_mcp_tools.py +0 -0
  74. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_processor_state.py +0 -0
  75. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_prompts.py +0 -0
  76. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_token_costs.py +0 -0
  77. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_token_rate.py +0 -0
  78. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/show_tools.py +0 -0
  79. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/start_flow.py +0 -0
  80. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/start_library_processing.py +0 -0
  81. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/stop_flow.py +0 -0
  82. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/stop_library_processing.py +0 -0
  83. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph/cli/unload_kg_core.py +0 -0
  84. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/SOURCES.txt +0 -0
  85. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/dependency_links.txt +0 -0
  86. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/entry_points.txt +0 -0
  87. {trustgraph_cli-2.2.3 → trustgraph_cli-2.2.4}/trustgraph_cli.egg-info/requires.txt +0 -0
  88. {trustgraph_cli-2.2.3 → 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
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 using the API
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
- # Convert to output format
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": type_display,
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()