trustgraph-cli 2.4.15__tar.gz → 2.4.17__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 (108) hide show
  1. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/PKG-INFO +1 -1
  2. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/pyproject.toml +2 -0
  3. trustgraph_cli-2.4.17/trustgraph/cli/get_de_core.py +111 -0
  4. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/get_kg_core.py +19 -58
  5. trustgraph_cli-2.4.17/trustgraph/cli/invoke_graph_rag.py +364 -0
  6. trustgraph_cli-2.4.17/trustgraph/cli/put_de_core.py +119 -0
  7. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/put_kg_core.py +23 -76
  8. trustgraph_cli-2.4.17/trustgraph/cli_version.py +1 -0
  9. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph_cli.egg-info/PKG-INFO +1 -1
  10. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph_cli.egg-info/SOURCES.txt +2 -0
  11. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph_cli.egg-info/entry_points.txt +2 -0
  12. trustgraph_cli-2.4.15/trustgraph/cli/invoke_graph_rag.py +0 -968
  13. trustgraph_cli-2.4.15/trustgraph/cli_version.py +0 -1
  14. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/README.md +0 -0
  15. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/setup.cfg +0 -0
  16. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/__init__.py +0 -0
  17. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/_iam.py +0 -0
  18. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/add_library_document.py +0 -0
  19. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/bootstrap_iam.py +0 -0
  20. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/change_password.py +0 -0
  21. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/create_api_key.py +0 -0
  22. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/create_user.py +0 -0
  23. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/create_workspace.py +0 -0
  24. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/delete_collection.py +0 -0
  25. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/delete_config_item.py +0 -0
  26. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/delete_flow_blueprint.py +0 -0
  27. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/delete_kg_core.py +0 -0
  28. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/delete_mcp_tool.py +0 -0
  29. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/delete_tool.py +0 -0
  30. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/delete_user.py +0 -0
  31. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/disable_user.py +0 -0
  32. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/dump_msgpack.py +0 -0
  33. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/dump_queues.py +0 -0
  34. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/enable_user.py +0 -0
  35. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/export_workspace_config.py +0 -0
  36. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/get_config_item.py +0 -0
  37. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/get_document_content.py +0 -0
  38. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/get_flow_blueprint.py +0 -0
  39. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/graph_to_turtle.py +0 -0
  40. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/import_workspace_config.py +0 -0
  41. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/init_pulsar_manager.py +0 -0
  42. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_agent.py +0 -0
  43. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_document_embeddings.py +0 -0
  44. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_document_rag.py +0 -0
  45. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_embeddings.py +0 -0
  46. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_graph_embeddings.py +0 -0
  47. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_llm.py +0 -0
  48. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_mcp_tool.py +0 -0
  49. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_nlp_query.py +0 -0
  50. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_prompt.py +0 -0
  51. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_row_embeddings.py +0 -0
  52. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_rows_query.py +0 -0
  53. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_sparql_query.py +0 -0
  54. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/invoke_structured_query.py +0 -0
  55. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/list_api_keys.py +0 -0
  56. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/list_collections.py +0 -0
  57. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/list_config_items.py +0 -0
  58. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/list_explain_traces.py +0 -0
  59. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/list_users.py +0 -0
  60. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/list_workspaces.py +0 -0
  61. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/load_doc_embeds.py +0 -0
  62. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/load_kg_core.py +0 -0
  63. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/load_knowledge.py +0 -0
  64. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/load_sample_documents.py +0 -0
  65. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/load_structured_data.py +0 -0
  66. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/load_turtle.py +0 -0
  67. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/login.py +0 -0
  68. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/monitor_prompts.py +0 -0
  69. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/put_config_item.py +0 -0
  70. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/put_flow_blueprint.py +0 -0
  71. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/query_graph.py +0 -0
  72. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/remove_library_document.py +0 -0
  73. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/reset_password.py +0 -0
  74. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/revoke_api_key.py +0 -0
  75. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/save_doc_embeds.py +0 -0
  76. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/set_collection.py +0 -0
  77. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/set_mcp_tool.py +0 -0
  78. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/set_prompt.py +0 -0
  79. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/set_token_costs.py +0 -0
  80. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/set_tool.py +0 -0
  81. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_config.py +0 -0
  82. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_explain_trace.py +0 -0
  83. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_extraction_provenance.py +0 -0
  84. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_flow_blueprints.py +0 -0
  85. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_flow_state.py +0 -0
  86. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_flows.py +0 -0
  87. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_graph.py +0 -0
  88. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_kg_cores.py +0 -0
  89. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_library_documents.py +0 -0
  90. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_library_processing.py +0 -0
  91. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_mcp_tools.py +0 -0
  92. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_parameter_types.py +0 -0
  93. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_processor_state.py +0 -0
  94. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_prompts.py +0 -0
  95. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_token_costs.py +0 -0
  96. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_token_rate.py +0 -0
  97. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/show_tools.py +0 -0
  98. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/start_flow.py +0 -0
  99. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/start_library_processing.py +0 -0
  100. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/stop_flow.py +0 -0
  101. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/stop_library_processing.py +0 -0
  102. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/unload_kg_core.py +0 -0
  103. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/update_user.py +0 -0
  104. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/verify_system_status.py +0 -0
  105. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph/cli/whoami.py +0 -0
  106. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph_cli.egg-info/dependency_links.txt +0 -0
  107. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/trustgraph_cli.egg-info/requires.txt +0 -0
  108. {trustgraph_cli-2.4.15 → trustgraph_cli-2.4.17}/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.4.15
3
+ Version: 2.4.17
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
@@ -37,6 +37,7 @@ tg-dump-msgpack = "trustgraph.cli.dump_msgpack:main"
37
37
  tg-dump-queues = "trustgraph.cli.dump_queues:main"
38
38
  tg-monitor-prompts = "trustgraph.cli.monitor_prompts:main"
39
39
  tg-get-flow-blueprint = "trustgraph.cli.get_flow_blueprint:main"
40
+ tg-get-de-core = "trustgraph.cli.get_de_core:main"
40
41
  tg-get-kg-core = "trustgraph.cli.get_kg_core:main"
41
42
  tg-get-document-content = "trustgraph.cli.get_document_content:main"
42
43
  tg-graph-to-turtle = "trustgraph.cli.graph_to_turtle:main"
@@ -77,6 +78,7 @@ tg-load-turtle = "trustgraph.cli.load_turtle:main"
77
78
  tg-load-knowledge = "trustgraph.cli.load_knowledge:main"
78
79
  tg-load-structured-data = "trustgraph.cli.load_structured_data:main"
79
80
  tg-put-flow-blueprint = "trustgraph.cli.put_flow_blueprint:main"
81
+ tg-put-de-core = "trustgraph.cli.put_de_core:main"
80
82
  tg-put-kg-core = "trustgraph.cli.put_kg_core:main"
81
83
  tg-remove-library-document = "trustgraph.cli.remove_library_document:main"
82
84
  tg-save-doc-embeds = "trustgraph.cli.save_doc_embeds:main"
@@ -0,0 +1,111 @@
1
+ """
2
+ Uses the knowledge service to fetch a document embeddings core which is
3
+ saved to a local file in msgpack format.
4
+ """
5
+
6
+ import argparse
7
+ import os
8
+ import msgpack
9
+
10
+ from trustgraph.api import Api
11
+
12
+ default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
13
+ default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
14
+ default_workspace = os.getenv("TRUSTGRAPH_WORKSPACE", "default")
15
+
16
+ def write_de(f, data):
17
+ msg = (
18
+ "de",
19
+ {
20
+ "m": {
21
+ "i": data["metadata"]["id"],
22
+ "m": data["metadata"]["root"],
23
+ "c": data["metadata"]["collection"],
24
+ },
25
+ "c": [
26
+ {
27
+ "i": ch["chunk_id"],
28
+ "v": ch["vector"],
29
+ }
30
+ for ch in data["chunks"]
31
+ ]
32
+ }
33
+ )
34
+ f.write(msgpack.packb(msg, use_bin_type=True))
35
+
36
+ def fetch(url, workspace, id, output, token=None):
37
+
38
+ api = Api(url=url, token=token, workspace=workspace)
39
+ socket = api.socket()
40
+
41
+ try:
42
+ de = 0
43
+
44
+ with open(output, "wb") as f:
45
+
46
+ for response in socket.get_de_core(id):
47
+
48
+ if "document-embeddings" in response:
49
+ de += 1
50
+ write_de(f, response["document-embeddings"])
51
+
52
+ print(f"Got: {de} document embeddings messages.")
53
+
54
+ finally:
55
+ socket.close()
56
+
57
+ def main():
58
+
59
+ parser = argparse.ArgumentParser(
60
+ prog='tg-get-de-core',
61
+ description=__doc__,
62
+ )
63
+
64
+ parser.add_argument(
65
+ '-u', '--url',
66
+ default=default_url,
67
+ help=f'API URL (default: {default_url})',
68
+ )
69
+
70
+ parser.add_argument(
71
+ '-w', '--workspace',
72
+ default=default_workspace,
73
+ help=f'Workspace (default: {default_workspace})',
74
+ )
75
+
76
+ parser.add_argument(
77
+ '--id', '--identifier',
78
+ required=True,
79
+ help=f'Document embeddings core ID',
80
+ )
81
+
82
+ parser.add_argument(
83
+ '-o', '--output',
84
+ required=True,
85
+ help=f'Output file'
86
+ )
87
+
88
+ parser.add_argument(
89
+ '-t', '--token',
90
+ default=default_token,
91
+ help='Authentication token (default: $TRUSTGRAPH_TOKEN)',
92
+ )
93
+
94
+ args = parser.parse_args()
95
+
96
+ try:
97
+
98
+ fetch(
99
+ url=args.url,
100
+ workspace=args.workspace,
101
+ id=args.id,
102
+ output=args.output,
103
+ token=args.token,
104
+ )
105
+
106
+ except Exception as e:
107
+
108
+ print("Exception:", e, flush=True)
109
+
110
+ if __name__ == "__main__":
111
+ main()
@@ -5,13 +5,11 @@ to a local file in msgpack format.
5
5
 
6
6
  import argparse
7
7
  import os
8
- import uuid
9
- import asyncio
10
- import json
11
- from websockets.asyncio.client import connect
12
8
  import msgpack
13
9
 
14
- default_url = os.getenv("TRUSTGRAPH_URL", 'ws://localhost:8088/')
10
+ from trustgraph.api import Api
11
+
12
+ default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
15
13
  default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
16
14
  default_workspace = os.getenv("TRUSTGRAPH_WORKSPACE", "default")
17
15
 
@@ -21,7 +19,7 @@ def write_triple(f, data):
21
19
  {
22
20
  "m": {
23
21
  "i": data["metadata"]["id"],
24
- "m": data["metadata"]["metadata"],
22
+ "m": data["metadata"]["root"],
25
23
  "c": data["metadata"]["collection"],
26
24
  },
27
25
  "t": data["triples"],
@@ -35,13 +33,13 @@ def write_ge(f, data):
35
33
  {
36
34
  "m": {
37
35
  "i": data["metadata"]["id"],
38
- "m": data["metadata"]["metadata"],
36
+ "m": data["metadata"]["root"],
39
37
  "c": data["metadata"]["collection"],
40
38
  },
41
39
  "e": [
42
40
  {
43
41
  "e": ent["entity"],
44
- "v": ent["vectors"],
42
+ "v": ent["vector"],
45
43
  }
46
44
  for ent in data["entities"]
47
45
  ]
@@ -49,54 +47,18 @@ def write_ge(f, data):
49
47
  )
50
48
  f.write(msgpack.packb(msg, use_bin_type=True))
51
49
 
52
- async def fetch(url, workspace, id, output, token=None):
53
-
54
- if not url.endswith("/"):
55
- url += "/"
56
-
57
- url = url + "api/v1/socket"
58
-
59
- if token:
60
- url = f"{url}?token={token}"
61
-
62
- mid = str(uuid.uuid4())
63
-
64
- async with connect(url) as ws:
65
-
66
- req = json.dumps({
67
- "id": mid,
68
- "workspace": workspace,
69
- "service": "knowledge",
70
- "request": {
71
- "operation": "get-kg-core",
72
- "workspace": workspace,
73
- "id": id,
74
- }
75
- })
50
+ def fetch(url, workspace, id, output, token=None):
76
51
 
77
- await ws.send(req)
52
+ api = Api(url=url, token=token, workspace=workspace)
53
+ socket = api.socket()
78
54
 
55
+ try:
79
56
  ge = 0
80
57
  t = 0
81
58
 
82
59
  with open(output, "wb") as f:
83
60
 
84
- while True:
85
-
86
- msg = await ws.recv()
87
-
88
- obj = json.loads(msg)
89
-
90
- if "response" not in obj:
91
- raise RuntimeError("No response?")
92
-
93
- response = obj["response"]
94
-
95
- if "error" in response:
96
- raise RuntimeError(obj["error"])
97
-
98
- if "eos" in response:
99
- if response["eos"]: break
61
+ for response in socket.get_kg_core(id):
100
62
 
101
63
  if "triples" in response:
102
64
  t += 1
@@ -108,7 +70,8 @@ async def fetch(url, workspace, id, output, token=None):
108
70
 
109
71
  print(f"Got: {t} triple, {ge} GE messages.")
110
72
 
111
- await ws.close()
73
+ finally:
74
+ socket.close()
112
75
 
113
76
  def main():
114
77
 
@@ -151,14 +114,12 @@ def main():
151
114
 
152
115
  try:
153
116
 
154
- asyncio.run(
155
- fetch(
156
- url=args.url,
157
- workspace=args.workspace,
158
- id=args.id,
159
- output=args.output,
160
- token=args.token,
161
- )
117
+ fetch(
118
+ url=args.url,
119
+ workspace=args.workspace,
120
+ id=args.id,
121
+ output=args.output,
122
+ token=args.token,
162
123
  )
163
124
 
164
125
  except Exception as e:
@@ -0,0 +1,364 @@
1
+ """
2
+ Uses the GraphRAG service to answer a question
3
+ """
4
+
5
+ import argparse
6
+ import os
7
+ import sys
8
+ from trustgraph.api import (
9
+ Api,
10
+ ExplainabilityClient,
11
+ RAGChunk,
12
+ ProvenanceEvent,
13
+ Question,
14
+ Grounding,
15
+ Exploration,
16
+ Focus,
17
+ Synthesis,
18
+ )
19
+
20
+ default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
21
+ default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
22
+ default_workspace = os.getenv("TRUSTGRAPH_WORKSPACE", "default")
23
+ default_collection = 'default'
24
+ default_entity_limit = 50
25
+ default_triple_limit = 30
26
+ default_max_subgraph_size = 150
27
+ default_max_path_length = 2
28
+ default_edge_score_limit = 30
29
+ default_edge_limit = 25
30
+
31
+ def _question_explainable_api(
32
+ url, flow_id, question_text, collection, entity_limit, triple_limit,
33
+ max_subgraph_size, max_path_length, edge_score_limit=30,
34
+ edge_limit=25, token=None, debug=False, workspace="default",
35
+ ):
36
+ """Execute graph RAG with explainability using the new API classes."""
37
+ api = Api(url=url, token=token, workspace=workspace)
38
+ socket = api.socket()
39
+ flow = socket.flow(flow_id)
40
+ explain_client = ExplainabilityClient(flow, retry_delay=0.2, max_retries=10)
41
+
42
+ try:
43
+ # Stream GraphRAG with explainability - process events as they arrive
44
+ for item in flow.graph_rag_explain(
45
+ query=question_text,
46
+ collection=collection,
47
+ entity_limit=entity_limit,
48
+ triple_limit=triple_limit,
49
+ max_subgraph_size=max_subgraph_size,
50
+ max_path_length=max_path_length,
51
+ edge_score_limit=edge_score_limit,
52
+ edge_limit=edge_limit,
53
+ ):
54
+ if isinstance(item, RAGChunk):
55
+ # Print response content
56
+ print(item.content, end="", flush=True)
57
+
58
+ elif isinstance(item, ProvenanceEvent):
59
+ # Use inline entity if available, otherwise fetch from graph
60
+ prov_id = item.explain_id
61
+ explain_graph = item.explain_graph or "urn:graph:retrieval"
62
+
63
+ entity = item.entity
64
+ if entity is None:
65
+ entity = explain_client.fetch_entity(
66
+ prov_id,
67
+ graph=explain_graph,
68
+ collection=collection
69
+ )
70
+
71
+ if entity is None:
72
+ if debug:
73
+ print(f"\n [warning] Could not fetch entity: {prov_id}", file=sys.stderr)
74
+ continue
75
+
76
+ # Display based on entity type
77
+ if isinstance(entity, Question):
78
+ print(f"\n [question] {prov_id}", file=sys.stderr)
79
+ if entity.query:
80
+ print(f" Query: {entity.query}", file=sys.stderr)
81
+ if entity.timestamp:
82
+ print(f" Time: {entity.timestamp}", file=sys.stderr)
83
+
84
+ elif isinstance(entity, Grounding):
85
+ print(f"\n [grounding] {prov_id}", file=sys.stderr)
86
+ if entity.concepts:
87
+ print(f" Concepts: {len(entity.concepts)}", file=sys.stderr)
88
+ for concept in entity.concepts:
89
+ print(f" - {concept}", file=sys.stderr)
90
+
91
+ elif isinstance(entity, Exploration):
92
+ print(f"\n [exploration] {prov_id}", file=sys.stderr)
93
+ if entity.edge_count:
94
+ print(f" Edges explored: {entity.edge_count}", file=sys.stderr)
95
+ if entity.entities:
96
+ print(f" Seed entities: {len(entity.entities)}", file=sys.stderr)
97
+ for ent in entity.entities:
98
+ label = explain_client.resolve_label(ent, collection)
99
+ print(f" - {label}", file=sys.stderr)
100
+
101
+ elif isinstance(entity, Focus):
102
+ print(f"\n [focus] {prov_id}", file=sys.stderr)
103
+ if entity.selected_edge_uris:
104
+ print(f" Focused on {len(entity.selected_edge_uris)} edge(s)", file=sys.stderr)
105
+
106
+ # Fetch full focus with edge details
107
+ focus_full = explain_client.fetch_focus_with_edges(
108
+ prov_id,
109
+ graph=explain_graph,
110
+ collection=collection
111
+ )
112
+ if focus_full and focus_full.edge_selections:
113
+ for edge_sel in focus_full.edge_selections:
114
+ if edge_sel.edge:
115
+ # Resolve labels for edge components
116
+ s_label, p_label, o_label = explain_client.resolve_edge_labels(
117
+ edge_sel.edge, collection
118
+ )
119
+ print(f" Edge: ({s_label}, {p_label}, {o_label})", file=sys.stderr)
120
+ if edge_sel.reasoning:
121
+ r_short = edge_sel.reasoning[:100] + "..." if len(edge_sel.reasoning) > 100 else edge_sel.reasoning
122
+ print(f" Reason: {r_short}", file=sys.stderr)
123
+
124
+ elif isinstance(entity, Synthesis):
125
+ print(f"\n [synthesis] {prov_id}", file=sys.stderr)
126
+ if entity.document:
127
+ print(f" Document: {entity.document}", file=sys.stderr)
128
+
129
+ else:
130
+ if debug:
131
+ print(f"\n [unknown] {prov_id} (type: {entity.entity_type})", file=sys.stderr)
132
+
133
+ print() # Final newline
134
+
135
+ finally:
136
+ socket.close()
137
+
138
+
139
+ def question(
140
+ url, flow_id, question, collection, entity_limit, triple_limit,
141
+ max_subgraph_size, max_path_length, edge_score_limit=50,
142
+ edge_limit=25, streaming=True, token=None,
143
+ explainable=False, debug=False, show_usage=False,
144
+ workspace="default",
145
+ ):
146
+
147
+ # Explainable mode uses the API to capture and process provenance events
148
+ if explainable:
149
+ _question_explainable_api(
150
+ url=url,
151
+ flow_id=flow_id,
152
+ question_text=question,
153
+ collection=collection,
154
+ entity_limit=entity_limit,
155
+ triple_limit=triple_limit,
156
+ max_subgraph_size=max_subgraph_size,
157
+ max_path_length=max_path_length,
158
+ edge_score_limit=edge_score_limit,
159
+ edge_limit=edge_limit,
160
+ token=token,
161
+ debug=debug,
162
+ workspace=workspace,
163
+ )
164
+ return
165
+
166
+ # Create API client
167
+ api = Api(url=url, token=token, workspace=workspace)
168
+
169
+ if streaming:
170
+ # Use socket client for streaming
171
+ socket = api.socket()
172
+ flow = socket.flow(flow_id)
173
+
174
+ try:
175
+ response = flow.graph_rag(
176
+ query=question,
177
+ collection=collection,
178
+ entity_limit=entity_limit,
179
+ triple_limit=triple_limit,
180
+ max_subgraph_size=max_subgraph_size,
181
+ max_path_length=max_path_length,
182
+ edge_score_limit=edge_score_limit,
183
+ edge_limit=edge_limit,
184
+ streaming=True
185
+ )
186
+
187
+ # Stream output
188
+ last_chunk = None
189
+ for chunk in response:
190
+ print(chunk.content, end="", flush=True)
191
+ last_chunk = chunk
192
+ print() # Final newline
193
+
194
+ if show_usage and last_chunk:
195
+ print(
196
+ f"Input tokens: {last_chunk.in_token} "
197
+ f"Output tokens: {last_chunk.out_token} "
198
+ f"Model: {last_chunk.model}",
199
+ file=sys.stderr,
200
+ )
201
+
202
+ finally:
203
+ socket.close()
204
+ else:
205
+ # Use REST API for non-streaming
206
+ flow = api.flow().id(flow_id)
207
+ result = flow.graph_rag(
208
+ query=question,
209
+ collection=collection,
210
+ entity_limit=entity_limit,
211
+ triple_limit=triple_limit,
212
+ max_subgraph_size=max_subgraph_size,
213
+ max_path_length=max_path_length,
214
+ edge_score_limit=edge_score_limit,
215
+ edge_limit=edge_limit,
216
+ )
217
+ print(result.text)
218
+
219
+ if show_usage:
220
+ print(
221
+ f"Input tokens: {result.in_token} "
222
+ f"Output tokens: {result.out_token} "
223
+ f"Model: {result.model}",
224
+ file=sys.stderr,
225
+ )
226
+
227
+ def main():
228
+
229
+ parser = argparse.ArgumentParser(
230
+ prog='tg-invoke-graph-rag',
231
+ description=__doc__,
232
+ )
233
+
234
+ parser.add_argument(
235
+ '-u', '--url',
236
+ default=default_url,
237
+ help=f'API URL (default: {default_url})',
238
+ )
239
+
240
+ parser.add_argument(
241
+ '-t', '--token',
242
+ default=default_token,
243
+ help='Authentication token (default: $TRUSTGRAPH_TOKEN)',
244
+ )
245
+
246
+ parser.add_argument(
247
+ '-w', '--workspace',
248
+ default=default_workspace,
249
+ help=f'Workspace (default: {default_workspace})',
250
+ )
251
+
252
+ parser.add_argument(
253
+ '-f', '--flow-id',
254
+ default="default",
255
+ help=f'Flow ID (default: default)'
256
+ )
257
+
258
+ parser.add_argument(
259
+ '-q', '--question',
260
+ required=True,
261
+ help=f'Question to answer',
262
+ )
263
+
264
+ parser.add_argument(
265
+ '-C', '--collection',
266
+ default=default_collection,
267
+ help=f'Collection ID (default: {default_collection})'
268
+ )
269
+
270
+ parser.add_argument(
271
+ '-e', '--entity-limit',
272
+ type=int,
273
+ default=default_entity_limit,
274
+ help=f'Entity limit (default: {default_entity_limit})'
275
+ )
276
+
277
+ parser.add_argument(
278
+ '--triple-limit',
279
+ type=int,
280
+ default=default_triple_limit,
281
+ help=f'Triple limit (default: {default_triple_limit})'
282
+ )
283
+
284
+ parser.add_argument(
285
+ '-s', '--max-subgraph-size',
286
+ type=int,
287
+ default=default_max_subgraph_size,
288
+ help=f'Max subgraph size (default: {default_max_subgraph_size})'
289
+ )
290
+
291
+ parser.add_argument(
292
+ '-p', '--max-path-length',
293
+ type=int,
294
+ default=default_max_path_length,
295
+ help=f'Max path length (default: {default_max_path_length})'
296
+ )
297
+
298
+ parser.add_argument(
299
+ '--edge-score-limit',
300
+ type=int,
301
+ default=default_edge_score_limit,
302
+ help=f'Semantic pre-filter limit before LLM scoring (default: {default_edge_score_limit})'
303
+ )
304
+
305
+ parser.add_argument(
306
+ '--edge-limit',
307
+ type=int,
308
+ default=default_edge_limit,
309
+ help=f'Max edges after LLM scoring (default: {default_edge_limit})'
310
+ )
311
+
312
+ parser.add_argument(
313
+ '--no-streaming',
314
+ action='store_true',
315
+ help='Disable streaming (use non-streaming mode)'
316
+ )
317
+
318
+ parser.add_argument(
319
+ '-x', '--explainable',
320
+ action='store_true',
321
+ help='Show provenance events: Question, Grounding, Exploration, Focus, Synthesis (implies streaming)'
322
+ )
323
+
324
+ parser.add_argument(
325
+ '--debug',
326
+ action='store_true',
327
+ help='Show debug output for troubleshooting'
328
+ )
329
+
330
+ parser.add_argument(
331
+ '--show-usage',
332
+ action='store_true',
333
+ help='Show token usage and model on stderr'
334
+ )
335
+
336
+ args = parser.parse_args()
337
+
338
+ try:
339
+
340
+ question(
341
+ url=args.url,
342
+ flow_id=args.flow_id,
343
+ question=args.question,
344
+ collection=args.collection,
345
+ entity_limit=args.entity_limit,
346
+ triple_limit=args.triple_limit,
347
+ max_subgraph_size=args.max_subgraph_size,
348
+ max_path_length=args.max_path_length,
349
+ edge_score_limit=args.edge_score_limit,
350
+ edge_limit=args.edge_limit,
351
+ streaming=not args.no_streaming,
352
+ token=args.token,
353
+ explainable=args.explainable,
354
+ debug=args.debug,
355
+ show_usage=args.show_usage,
356
+ workspace=args.workspace,
357
+ )
358
+
359
+ except Exception as e:
360
+
361
+ print("Exception:", e, flush=True)
362
+
363
+ if __name__ == "__main__":
364
+ main()